题目
https://www.luogu.com.cn/problem/P1501
一棵 nn 个点的树,每个点的初始权值为 11。
对于这棵树有 qq 个操作,每个操作为以下四种操作之一:
- u v c:将 uu 到 vv 的路径上的点的权值都加上自然数 cc;
- u1 v1 u2 v2:将树中原有的边 (u_1,v_1)(u
1
,v
1
) 删除,加入一条新边 (u_2,v_2)(u
2
,v
2
),保证操作完之后仍然是一棵树;
- u v c:将 uu 到 vv 的路径上的点的权值都乘上自然数 cc;
/ u v:询问 uu 到 vv 的路径上的点的权值和,将答案对 51061 取模。
思路
LCT练习题,结果我调了一个晚上+一个中午……
然后发现是pushdown打错了
这里我说一下要注意的几个点:这题要维护两个标记,更新乘法标记时要同时更新加法标记
还有要开long long!!
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+77,mod=51061;
int ch[N][2],fa[N],rev[N],Q[N],top,n,q;
ll _add[N],_mul[N],sum[N],siz[N],a[N];
bool isroot(int x)
{
return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
bool get(int x)
{
return ch[fa[x]][1]==x;
}
void mul(int x,ll c)
{
sum[x]*=c; sum[x]%=mod;
a[x]*=c; a[x]%=mod;
_mul[x]*=c; _mul[x]%=mod;
_add[x]*=c; _add[x]%=mod;
}
void add(int x,ll c)
{
sum[x]+=c*(ll)siz[x]; sum[x]%=mod;
a[x]+=c; a[x]%=mod;
_add[x]+=c; _add[x]%=mod;
}
void pushdown(int x)
{
if(rev[x])
{
rev[ch[x][0]]^=1; rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
rev[x]=0;
}
if(_mul[x]!=1)
{
if(ch[x][0]) mul(ch[x][0],_mul[x]);
if(ch[x][1]) mul(ch[x][1],_mul[x]);
_mul[x]=1;
}
if(_add[x])
{
if(ch[x][0]) add(ch[x][0],_add[x]);
if(ch[x][1]) add(ch[x][1],_add[x]);
_add[x]=0;
}
}
void update(int x)
{
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
sum[x]=(sum[ch[x][0]]+sum[ch[x][1]]+a[x])%mod;
}
void rotate(int x)
{
int y=fa[x],z=fa[y],l=get(x),r=l^1;
if(!isroot(y)) ch[z][get(y)]=x;
fa[x]=z; fa[y]=x; fa[ch[x][r]]=y; ch[y][l]=ch[x][r]; ch[x][r]=y;
update(x); update(y);
}
void splay(int x)
{
top=0;
Q[++top]=x;
for(int i=x; !isroot(i); i=fa[i])
Q[++top]=fa[i];
while(top) pushdown(Q[top--]);
while(!isroot(x))
{
int y=fa[x],z=fa[y],d1=ch[y][1]==x,d2=ch[z][1]==y;
if(!isroot(y))
{
if(d1==d2) rotate(y),rotate(x); else rotate(x),rotate(x);
}
else rotate(x);
}
update(x);
}
void add(int x,int c)
{
_add[x]=(_add[x]+c)%mod; sum[x]=(sum[x]+siz[x]*c)%mod; a[x]=(a[x]+c)%mod;
}
void mul(int x,int c)
{
_add[x]=_add[x]*c%mod; _mul[x]=_mul[x]*c%mod; sum[x]=sum[x]*c%mod; a[x]=(a[x]*c)%mod;
}
void access(int x)
{
for(int t=0; x; t=x,x=fa[x])
{
splay(x),ch[x][1]=t;
update(x);
if(t) fa[t]=x;
}
}
void makeroot(int x)
{
access(x);
splay(x);
rev[x]^=1;
}
void link(int x,int y)
{
makeroot(x); fa[x]=y;
}
void cut(int x,int y)
{
makeroot(x); access(y); splay(y); ch[y][0]=fa[x]=0; update(y);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1; i<=n; i++) siz[i]=1,_mul[i]=1,a[i]=1;
for(int i=1,x,y; i<n; i++)
{
scanf("%d%d",&x,&y); link(x,y);
}
while(q--)
{
char op='$';
while(op!='+'&&op!='-'&&op!='*'&&op!='/') op=getchar();
if(op=='+')
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
makeroot(x); access(y); splay(y); add(y,c);
}
else if(op=='-')
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2); cut(x1,y1); link(x2,y2);
}
else if(op=='*')
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
makeroot(x); access(y); splay(y); mul(y,c);
}
else if(op=='/')
{
int x,y;
scanf("%d%d",&x,&y);
makeroot(x);
access(y); splay(y);
printf("%lld\n",sum[y]);
}
}
}