luogu P1501 [国家集训队]Tree II

背景:

调了一个下午,终于 A C AC AC了。
人生第一个 l a z y lazy lazy版的 L C T LCT LCT模板。
不是特别难,难度虚高。

题目传送门:

https://www.luogu.org/problemnew/show/P1501

题意:

维护一棵树,支持加边,删边,修改路径(加和乘),求路径和。

思路:

支持删边的显然用 L C T LCT LCT
要打 l a z y lazy lazy
注意:由优先级可知要先乘后加,跟线段树差不多。
注意:打 l a z y lazy lazy标记与线段树和 s p l a y splay splay不同,要打在下面,因为 a c c e s s access access操作是从下往上的,打在上面会被覆盖掉。

代码:

#include
#include
#include
#define LL long long
#define mod 51061
using namespace std;
	struct node{int fa,op,size,son[2];LL d,lazy1,lazy2,sum;} tr[300010];
	int n,m;
bool isroot(int x)
{
	return tr[tr[x].fa].son[0]!=x&&tr[tr[x].fa].son[1]!=x;
}
bool isson(int x)
{
	return x==tr[tr[x].fa].son[1];
}
void change(int x)
{
	if(!x) return;
	swap(tr[x].son[0],tr[x].son[1]);
	tr[x].op^=1;
}
void LAZY(int x)
{
	int lc=tr[x].son[0],rc=tr[x].son[1];
	if(tr[x].lazy1!=1)
	{
		tr[lc].lazy1=tr[lc].lazy1*tr[x].lazy1%mod;tr[lc].d=tr[lc].d*tr[x].lazy1%mod;tr[lc].sum=tr[lc].sum*tr[x].lazy1%mod;
		tr[rc].lazy1=tr[rc].lazy1*tr[x].lazy1%mod;tr[rc].d=tr[rc].d*tr[x].lazy1%mod;tr[rc].sum=tr[rc].sum*tr[x].lazy1%mod;
		tr[lc].lazy2=tr[lc].lazy2*tr[x].lazy1%mod;
		tr[rc].lazy2=tr[rc].lazy2*tr[x].lazy1%mod;
		tr[x].lazy1=1;
	}
	if(tr[x].lazy2)
	{
		tr[lc].lazy2=(tr[lc].lazy2+tr[x].lazy2)%mod;tr[lc].d=(tr[lc].d+tr[x].lazy2%mod)%mod;tr[lc].sum=(tr[lc].sum+tr[x].lazy2*tr[lc].size%mod)%mod;
		tr[rc].lazy2=(tr[rc].lazy2+tr[x].lazy2)%mod;tr[rc].d=(tr[rc].d+tr[x].lazy2%mod)%mod;tr[rc].sum=(tr[rc].sum+tr[x].lazy2*tr[rc].size%mod)%mod;
		tr[x].lazy2=0;
	}
}
void pushup(int x)
{
	int lc=tr[x].son[0],rc=tr[x].son[1];
	tr[x].sum=((tr[lc].sum+tr[rc].sum)%mod+tr[x].d)%mod;
	tr[x].size=tr[lc].size+tr[rc].size+1;
}
void pushdown(int x)
{
	if(tr[x].op)
	{
		change(tr[x].son[0]),change(tr[x].son[1]);
		tr[x].op=0;
	}
	LAZY(x);
}
void rot(int x)
{
	int w=isson(x),y=tr[x].fa,yy=tr[y].fa;
	tr[y].son[w]=tr[x].son[w^1];
	if(tr[y].son[w]) tr[tr[y].son[w]].fa=y;
	tr[x].fa=yy;
	if(!isroot(y)) tr[yy].son[isson(y)]=x;
	tr[x].son[w^1]=y;tr[y].fa=x;
	pushup(y);
}
int sta[300010];
int top;
void splay(int x)
{
	sta[top=1]=x;
	for(int i=x;!isroot(i);i=tr[i].fa)
		sta[++top]=tr[i].fa;
	while(top) pushdown(sta[top--]);
	for(int y=tr[x].fa;!isroot(x);rot(x),y=tr[x].fa)
		if(!isroot(y)) isson(x)^isson(y)?rot(x):rot(y);
	pushup(x);
}
void access(int x)
{
	for(int y=0;x;y=x,x=tr[x].fa)
		splay(x),tr[x].son[1]=y,pushup(x);
}
void makeroot(int x)
{
	access(x);splay(x);change(x);
}
void link(int x,int y)
{
	makeroot(x);
	tr[x].fa=y;
}
void split(int x,int y)
{
	makeroot(x);access(y);splay(y);
}
void del(int x,int y)
{
	split(x,y);
	tr[x].fa=tr[y].son[0]=0;
}
void work1(int x,int y,int z)
{
	split(x,y);
	LAZY(y);
	tr[y].d=(tr[y].d+z)%mod;
	tr[y].sum=(tr[y].sum+z*tr[y].size)%mod;
	tr[y].lazy2=(tr[y].lazy2+z)%mod;
}
void work2(int x,int y,int z)
{
	split(x,y);
	LAZY(y);
	tr[y].d=tr[y].d*z%mod;
	tr[y].sum=tr[y].sum*z%mod;
	tr[y].lazy1=tr[y].lazy1*z%mod;
}
LL query(int x,int y)
{
	split(x,y);
	return tr[y].sum;
}
int main()
{
	char s[5];
	int x,y,z;
	scanf("%d %d",&n,&m);
	tr[0]=(node){0,0,0,0,0,0,0,0,0};
	for(int i=1;i<=n;i++)
		tr[i]=(node){0,0,1,0,0,1,1,0,1};
	for(int i=1;i<n;i++)
	{
		scanf("%d %d",&x,&y);
		link(x,y);
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%s",s+1);
		switch(s[1])
		{
			case '+':scanf("%d %d %d",&x,&y,&z);work1(x,y,z);break;
			case '-':scanf("%d %d",&x,&y);del(x,y);scanf("%d %d",&x,&y);link(x,y);break;
			case '*':scanf("%d %d %d",&x,&y,&z);work2(x,y,z);break;
			case '/':scanf("%d %d",&x,&y);printf("%lld\n",query(x,y));break;
		}
	}
}

你可能感兴趣的:(#,LCT)