萌新刚学LCT,有一组数据一直为0求助
查看原帖
萌新刚学LCT,有一组数据一直为0求助
231190
smyslenny楼主2021/9/7 20:28

rt

就过了一个点,其他点都应该输出负数,而我的输出为0,通过某神奇方法弄了一组数据,然后一直都是有一个点为 0 ,看了第一页的解改了改还是一直错,实在改不出来了。

下面是代码

/*
* @Author: smyslenny
* @Date:    2021.09.07
* @Title:   P2590 [ZJOI2008]树的统计
* @Main idea:LCT
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>

#define int long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)
#define lson(p) tree[(p)].ch[0]
#define rson(p) tree[(p)].ch[1]

using namespace std;
const int mod=998244353;
const int M=5e5+5;
int n,m,u[M],v[M];
int read()
{
	int x=0,y=1;
	char c=getchar();
	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
	return y?x:-x;
}
struct tr{
	int ch[3],sum,laz,Max,val;
}tree[M<<2];
void push_up(int p)
{
	tree[p].sum=tree[lson(p)].sum+tree[rson(p)].sum+tree[p].val;
	tree[p].Max=max(tree[lson(p)].Max,max(tree[rson(p)].Max,tree[p].val));
}
/*
void ff(int p) 
{
	swap(lson(p),rson(p));
	tree[p].laz^=1;
}
*/
void push_down(int p)
{
	if(!tree[p].laz) return;
	if(lson(p)) tree[lson(p)].laz^=1;
	if(rson(p)) tree[rson(p)].laz^=1;
	swap(lson(p),rson(p));
	tree[p].laz=0;
}
int f[M];
bool isroot(int x)//判断当前点是否是实链的根节点
{//当前点是根节点因为这它认父亲,父亲不认儿子 
	return lson(f[x])!=x && rson(f[x])!=x; 
}

void rotate(int x,int op)
{
	int y=f[x];
	if(!isroot(y))
		tree[f[y]].ch[rson(f[y])==y]=x;//原先父亲节点与其父亲节点的边断开,连上现在的这个点 
	f[x]=f[y];//儿子节点的爸爸换成爷爷 
	if(tree[x].ch[op])//儿子节点op儿子有的话,改变他的父亲为父亲 
		f[tree[x].ch[op]]=y;
	tree[y].ch[!op]=tree[x].ch[op];//父亲的儿子变成儿子的儿子 
	f[y]=x;//父亲的父亲变成儿子 
	tree[x].ch[op]=y;//儿子的对应儿子变成父亲
	push_up(y); 
	//注:注释里的父亲,儿子,爷爷,都表示没变化之前的称谓 
}
int sta[M],top;//为了将懒惰标记一气儿下传 
void splay(int x)
{
	top=0;
	sta[++top]=x;
	for(int i=x;!isroot(i);i=f[i]) sta[++top]=f[i];
	while(top) push_down(sta[top--]);//splay之前先将要旋转的链上的懒惰标记全部下穿,免去了边旋转边下传的麻烦
	while(!isroot(x))//当前点不是根 
	{
		if(!isroot(f[x]))//父亲也不是根 
		{	
			if((rson(f[x])==x)^(rson(f[f[x]])==f[x]))//不在一边 
				rotate(x,lson(f[x])==x);//旋转当前节点 
			else
				rotate(f[x],lson(f[f[x]])==f[x]);//链的情况,旋转父亲节点才能改变形态,旋转父亲节点 
		}
		rotate(x,lson(f[x])==x);
	}
	push_up(x);
}

void access(int p)//将当前点通到根节点 
{//断开当前点连的实链,到根节点连一条实链 
	int t=0;//因为当前点是这条链的最后一个点,旋转到根之后右边的点就是当前点之后的点,也就是要断开的店 
	while(p)
	{
		splay(p);//把 p 伸展到根节点, 
		rson(p)=t;//不断让父亲向它连边,也就是连上了实边 
		t=p;
		p=f[p];
		push_up(p);
	}
}
void makeroot(int p)//是当前点变成原树里的根节点 
{
	access(p);//到根节点连实链,也就是一颗 splay
	splay(p);//将当前点转到根节点
	tree[p].laz^=1;//由于 x 点是最后一个,当前为根节点时所有的点都在他的左边,rev一下让所有的点都在他右边,就变成了根了、
}
void link(int x,int y)//连边
{
	makeroot(x);//使p变成根节点
	f[x]=y;//x变成y的父亲,也就是连了边
}
int find(int x)//找原树的根 
{
	access(x);//x到根建一颗splay
	splay(x);//将 x 伸展到根节点
	while(lson(x)) push_down(x),x=lson(x);//因为原树根节点肯定就是中序遍历的第一个点,也就是最顶上的
	return x;// splay的最左边的儿子,一直找左儿子就行了 
}
void cut(int x,int y)//删边
{
	makeroot(x);//x变成根节点
	/*access(y);//y通向 x 减了一个实链,也就是一颗 splay,因为 x,y之间有边,所以这颗splay 里面只有两个点
	splay(y);//将 y 转到顶部 
	if(lson(y)!=x ||rson(x)) return;
	f[x]=0;//删去原来连边的信息 
	lson(y)=0;
	push_up(x);
	push_up(y);*/
	if(find(y) == x && f[x]==y && !rson(x))
	{
		lson(y)=0;
		f[x]=0;
		push_up(y);
	}
}
int query(int x,int y,int opt)
{
	makeroot(x);//x成为根 
	access(y);//生成实链 
	splay(y);//y伸展到根,也就统计了这条链上的答案 
	return opt?tree[y].sum:tree[y].Max;
}
void update(int x,int y)//把 x 的值改为 y 
{
	splay(x);//把 x 转到顶部
	tree[x].val=y;
	push_up(x); 
}

signed main()
{
//	freopen("1.in","r",stdin);
//	freopen("tree.out","w",stdout);
	n=read();
	for(int i=1;i<n;i++)
		u[i]=read(),v[i]=read();
	tree[0].Max=-INF;
	for(int i=1;i<n;i++) link(u[i],v[i]); 
	for(int i=1;i<=n;i++)
	{
		int x=read();
		tree[i].sum=tree[i].Max=tree[i].val=x;
	}
	m=read();
	while(m--)
	{
		char opt[10];
		scanf("%s",opt);
		int x=read(),y=read();
		if(opt[1]=='M') printf("%lld\n",query(x,y,0));
		else if(opt[1]=='S') printf("%lld\n",query(x,y,1));
		else if(opt[1]=='H') update(x,y);
	}
	return 0;
}
2021/9/7 20:28
加载中...