一棵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的余数。
标签:
2016-06-01 08:50:36
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2631
注意加和乘的标记下传问题。
还有就是split后,要分清x和y哪个是祖先。
pushup在access和rotate后都要进行。
这题还卡常数,开ll就会T,开unsigned int即可。
1 #include<bits/stdc++.h> 2 #define inf 1000000000 3 #define uint unsigned int 4 #define N 100005 5 #define mod 51061 6 using namespace std; 7 int read(){ 8 int x=0,f=1;char ch=getchar(); 9 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 10 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 11 return x*f; 12 } 13 int n,q; 14 char ch[5]; 15 namespace LCT{ 16 int ch[N][2],fa[N],sz[N];bool rev[N]; 17 uint cj[N],add[N],val[N],sum[N]; 18 inline bool isroot(int x){ 19 if(ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x)return 1;return 0; 20 } 21 void change(int x,int c,int a){ 22 if(!x)return; 23 val[x]=(val[x]*c+a)%mod; 24 sum[x]=(sum[x]*c+a*sz[x])%mod; 25 add[x]=(add[x]*c+a)%mod; 26 cj[x]=(cj[x]*c)%mod; 27 } 28 void pushdown(int x){ 29 if(rev[x]){ 30 rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;rev[x]^=1; 31 swap(ch[x][0],ch[x][1]); 32 } 33 if(cj[x]!=1||add[x]!=0){ 34 change(ch[x][0],cj[x],add[x]); 35 change(ch[x][1],cj[x],add[x]); 36 } 37 cj[x]=1;add[x]=0; 38 } 39 void Pushdown(int x){ 40 if(!isroot(x))Pushdown(fa[x]); 41 pushdown(x); 42 } 43 void pushup(int x){ 44 sum[x]=(sum[ch[x][0]]+sum[ch[x][1]]+val[x])%mod; 45 sz[x]=(sz[ch[x][0]]+sz[ch[x][1]]+1)%mod; 46 } 47 void rotate(int x){ 48 int y=fa[x],k=ch[y][1]==x; 49 if(!isroot(y))ch[fa[y]][ch[fa[y]][1]==y]=x; 50 fa[x]=fa[y]; 51 fa[ch[x][!k]]=y; 52 fa[y]=x; 53 ch[y][k]=ch[x][!k]; 54 ch[x][!k]=y; 55 pushup(y);pushup(x); 56 } 57 void splay(int x){ 58 Pushdown(x); 59 for(int y=fa[x];!isroot(x);y=fa[x]){ 60 if(!isroot(y)){ 61 if((ch[fa[y]][ch[fa[y]][1]==y])!=(ch[y][1]==x))rotate(x); 62 else rotate(y); 63 }rotate(x); 64 } 65 } 66 inline void access(int x){ 67 int y=0; 68 while(x){ 69 splay(x); 70 ch[x][1]=y;pushup(x); 71 x=fa[y=x]; 72 } 73 } 74 inline void moveroot(int x){ 75 access(x);splay(x);rev[x]^=1; 76 } 77 inline void link(int x,int y){ 78 moveroot(x);fa[x]=y;splay(x); 79 } 80 inline void cut(int x,int y){ 81 moveroot(x);access(y);splay(y);ch[y][0]=fa[x]=0; 82 } 83 inline void split(int x,int y){ 84 moveroot(y);access(x);splay(x); 85 } 86 } 87 int main(){ 88 n=read();q=read(); 89 for(int i=1;i<=n;i++)LCT::val[i]=LCT::sum[i]=LCT::cj[i]=LCT::sz[i]=1; 90 for(int i=1;i<n;i++)LCT::link(read(),read()); 91 while(q--){ 92 scanf("%s",ch); 93 int u=read(),v=read(); 94 if(ch[0]==‘+‘)LCT::split(u,v),LCT::change(u,1,read()); 95 else if(ch[0]==‘-‘){ 96 LCT::cut(u,v);u=read();v=read();LCT::link(u,v); 97 } 98 else if(ch[0]==‘*‘)LCT::split(u,v),LCT::change(u,read(),0); 99 else LCT::split(u,v),printf("%d\n",LCT::sum[u]%mod); 100 } 101 return 0; 102 }
一棵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的余数。
数据规模和约定
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
标签:
原文地址:http://www.cnblogs.com/wjyi/p/5548401.html