题目描述
一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:
-
+ u v c
:将u到v的路径上的点的权值都加上自然数c; -
- u1 v1 u2 v2
:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树; -
* u v c
:将u到v的路径上的点的权值都乘上自然数c; -
/ u v
:询问u到v的路径上的点的权值和,求出答案对于51061的余数。
输入输出格式
输入格式:
第一行两个整数n,q
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
输出格式:
对于每个/对应的答案输出一行
输入输出样例
说明
10%的数据保证,1<=n,q<=2000
另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链
另外35%的数据保证,1<=n,q<=5*10^4,没有-操作
100%的数据保证,1<=n,q<=10^5,0<=c<=10^4
By (伍一鸣)
题解:这题其实没有什么很难的地方,主要考点就是lct的打标记(还是两个orz),显然链修改跟线段树的打标记是一样的
就是酱紫了~
结果%=写成%调了一个晚上2333
代码如下
#include<map> #include<set> #include<queue> #include<cmath> #include<cstdio> #include<string> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define N 100010 #define mod 51061 #define lson ch[x][0] #define rson ch[x][1] #define int long long using namespace std; int tag1[N],tag2[N],tag3[N],sum[N],sz[N],f[N],ch[N][2],w[N]; int not_root(int now) { int x=f[now]; return lson==now||rson==now; } int push_up(int x) { sum[x]=(sum[lson]+sum[rson]+w[x])%mod; sz[x]=sz[lson]+sz[rson]+1; } int rev(int x) { swap(lson,rson); tag1[x]^=1; } int add(int x,int cost) { sum[x]+=cost*sz[x]; sum[x]%=mod; w[x]+=cost; w[x]%=mod; tag2[x]+=cost; tag2[x]%=mod; } int mul(int x,int cost) { sum[x]*=cost; sum[x]%=mod; w[x]*=cost; w[x]%=mod; tag3[x]*=cost; tag3[x]%=mod; tag2[x]*=cost; tag2[x]%=mod; } int push_down(int x) { if(tag3[x]!=1) { mul(lson,tag3[x]); mul(rson,tag3[x]); tag3[x]=1; } if(tag2[x]) { add(lson,tag2[x]); add(rson,tag2[x]); tag2[x]=0; } if(tag1[x]) { rev(lson); rev(rson); tag1[x]=0; } } int rotate(int x) { int y=f[x],z=f[y],kd=ch[y][1]==x,xs=ch[x][!kd]; if(not_root(y)) { ch[z][ch[z][1]==y]=x; } ch[x][!kd]=y; ch[y][kd]=xs; if(xs) f[xs]=y; f[y]=x; f[x]=z; push_up(y); } int push_all(int x) { if(not_root(x)) { push_all(f[x]); } push_down(x); } int splay(int x) { int y,z; push_all(x); while(not_root(x)) { y=f[x],z=f[y]; if(not_root(y)) { (ch[y][0]==x)^(ch[z][0]==y)?rotate(x):rotate(y); } rotate(x); } push_up(x); } int access(int x) { for(int y=0; x; y=x,x=f[x]) { splay(x); rson=y; push_up(x); } } int make_root(int x) { access(x); splay(x); rev(x); } int split(int x,int y) { make_root(x); access(y); splay(y); } int link(int x,int y) { make_root(x); f[x]=y; } int cut(int x,int y) { split(x,y); f[x]=ch[y][0]=0; } char s[3]; int n,m; signed main() { scanf("%lld %lld",&n,&m); for(int i=1; i<=n; i++) { sum[i]=w[i]=tag3[i]=sz[i]=1; } for(int i=1; i<n; i++) { int from,to; scanf("%lld %lld",&from,&to); link(from,to); } for(int i=1; i<=m; i++) { scanf("%s",s); if(s[0]=='*') { int x,y,cost; scanf("%lld %lld %lld",&x,&y,&cost); split(y,x); mul(x,cost); } if(s[0]=='-') { int u1,v1,u2,v2; scanf("%lld %lld %lld %lld",&u1,&v1,&u2,&v2); cut(u1,v1); link(u2,v2); } if(s[0]=='+') { int x,y,cost; scanf("%lld %lld %lld",&x,&y,&cost); split(y,x); add(x,cost); } if(s[0]=='/') { int u,v; scanf("%lld %lld",&u,&v); split(u,v); printf("%lld ",sum[v]); } } }