调了一个下午,终于 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;
}
}
}