题目传送门
题目大意: 给一棵树,若干种操作:路径加,路径乘,删边加边,求路径和。
看到删边加边就知道是 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);
}
}
}