国家集训队 Tree II 题解

题目传送门

题目大意: 给一棵树,若干种操作:路径加,路径乘,删边加边,求路径和。

题解

看到删边加边就知道是 L C T LCT LCT 了。

路径加路径乘都是打个标记的事,但是在更新 s u m sum sum 的时候, s u m sum sum 不仅要乘上乘法标记,还要加上加法标记乘 s i z e size size 的积。( s i z e size size 是子树大小)

以及这题的模数的平方刚好爆 i n t int int,所以要开 l o n g   l o n g long~long long long

以及我长时间 WA 5分的原因可能是比较稀有的……

众所周知, l a z y lazy lazy 标记有两种写法,第一种在得到 l a z y lazy lazy 标记时更新自己的 v a l u e value value 以及 s u m sum sum,然后在 p u s h d o w n pushdown pushdown 的时候更新儿子的 v a l u e value value s u m sum sum;第二种是得到 l a z y lazy lazy 标记的时候不更新,在 p u s h d o w n pushdown pushdown 的时候更新自己的 v a l u e value value s u m sum sum

对于线段树而言,这两种写法是等价的,但是对于 S p l a y Splay Splay 而言,第二种写法却是错的。因为 r o t a t e rotate rotate 操作里面,旋转完之后父亲变成了我的儿子,要 u p d a t e ( f a ) update(fa) update(fa) 然后 u p d a t e ( x ) update(x) update(x),如果用第二种写法的话就会错,原因想想就能明白。

代码如下:

#include 
#include 
#include 
using namespace std;
#define maxn 100010
#define mod 51061
#define ll long long

struct node{
	ll val,sum,lazyplus,lazytimes;
	int size,lazy;
	node *zuo,*you,*fa;
	node():val(1),sum(1),lazy(0),lazyplus(0),lazytimes(1),zuo(NULL),you(NULL),fa(NULL){}
	void update(ll plus,ll times)
	{
		sum=(sum*times%mod+plus*size%mod)%mod;
		val=(val*times%mod+plus)%mod;
	}
	void pushdown()
	{
		if(lazy||lazyplus||lazytimes!=1)
		{
			if(zuo!=NULL)zuo->lazy^=lazy,zuo->lazyplus=(zuo->lazyplus*lazytimes%mod+lazyplus)%mod,zuo->lazytimes=zuo->lazytimes*lazytimes%mod,zuo->update(lazyplus,lazytimes);
			if(you!=NULL)you->lazy^=lazy,you->lazyplus=(you->lazyplus*lazytimes%mod+lazyplus)%mod,you->lazytimes=you->lazytimes*lazytimes%mod,you->update(lazyplus,lazytimes);
			if(lazy)swap(zuo,you);
			lazy=0;lazyplus=0;lazytimes=1;
		}
	}
	void check()
	{
		size=1,sum=val;
		if(zuo!=NULL)size+=zuo->size,sum=(sum+zuo->sum)%mod;
		if(you!=NULL)size+=you->size,sum=(sum+you->sum)%mod;
	}
	bool notroot(){return fa!=NULL&&(fa->zuo==this||fa->you==this);}
};
node *root[maxn];
node *zhan[maxn];
int t=0;
void rotate(node *x)
{
	node *fa=x->fa,*gfa=fa->fa;
	if(fa->zuo==x)
	{
		fa->zuo=x->you;
		if(x->you!=NULL)x->you->fa=fa;
		x->you=fa;
	}
	else
	{
		fa->you=x->zuo;
		if(x->zuo!=NULL)x->zuo->fa=fa;
		x->zuo=fa;
	}
	fa->fa=x;x->fa=gfa;
	if(gfa!=NULL&&gfa->zuo==fa)gfa->zuo=x;
	if(gfa!=NULL&&gfa->you==fa)gfa->you=x;
	fa->check();x->check();
}
#define witch(x) (x->fa->zuo==x)
void splay(node *x)
{
	node *now=x;
	zhan[++t]=now;
	while(now->notroot())zhan[++t]=now=now->fa;
	while(t)zhan[t--]->pushdown();
	while(x->notroot())
	{
		if(x->fa->notroot()&&witch(x)==witch(x->fa))rotate(x->fa),rotate(x);
		else rotate(x);
	}
}
void access(node *x)
{
	for(node *y=NULL;x!=NULL;y=x,x=x->fa)
	splay(x),x->you=y,x->check();
}
void makeroot(node *x)
{
	access(x);splay(x);
	x->lazy^=1;x->pushdown();
}
void split(node *x,node *y)
{
	makeroot(x);access(y);
	splay(x);
}
void link(node *x,node *y)
{
	makeroot(x);
	x->fa=y;
}
void del(node *x,node *y)
{
	split(x,y);
	y->fa=x->you=NULL;
	x->check();
}
int n,m;

int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	root[i]=new node();
	for(int i=1,x,y;i<n;i++)
	scanf("%d %d",&x,&y),link(root[x],root[y]);
	for(int i=1;i<=m;i++)
	{
		char s[3];
		int x,y,xx,yy;
		scanf("%s",s);
		if(s[0]=='+')
		{
			scanf("%d %d %d",&x,&y,&xx);
			split(root[x],root[y]);
			root[x]->lazyplus=(root[x]->lazyplus+(ll)xx)%mod;
			root[x]->update(xx,1);
			root[x]->pushdown();
		}
		if(s[0]=='-')
		{
			scanf("%d %d %d %d",&x,&y,&xx,&yy);
			del(root[x],root[y]);link(root[xx],root[yy]);
		}
		if(s[0]=='*')
		{
			scanf("%d %d %d",&x,&y,&xx);
			split(root[x],root[y]);
			root[x]->lazytimes=root[x]->lazytimes*(ll)xx%mod;
			root[x]->lazyplus=root[x]->lazyplus*(ll)xx%mod;
			root[x]->update(0,xx);
			root[x]->pushdown();
		}
		if(s[0]=='/')
		{
			scanf("%d %d",&x,&y);
			split(root[x],root[y]);
			printf("%lld\n",root[x]->sum);
		}
	}
}

你可能感兴趣的:(题解_杂)