[国家集训队2012]tree(伍一鸣)

[国家集训队2012]tree(伍一鸣)

 

tree(伍一鸣)
时间限制:2.5s   内存限制:64.0M
 

【问题描述】

一棵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行,每行描述一个操作

【输出格式】

对于每个/对应的答案输出一行

【样例输入】

3 2
1 2
2 3
* 1 3 4
/ 1 1

【样例输出】

4

【数据规模和约定】

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
 
继续水板子...
感觉已经蛮熟练了...
  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 using namespace std;
  4 const int mod=51061;
  5 const int inf=1e5+5;
  6 int n,q,tot,fi[inf],to[inf<<1],next[inf<<1];
  7 int ch[inf][2],fa[inf],rev[inf],siz[inf];
  8 ll add[inf],mul[inf],sum[inf],v[inf];
  9 void edge_add(int x,int y){
 10     to[++tot]=y;
 11     next[tot]=fi[x];
 12     fi[x]=tot;
 13 }
 14 void dfs(int x,int f){
 15     fa[x]=f;
 16     siz[x]=1;
 17     v[x]=1;
 18     mul[x]=1;
 19     add[x]=0;
 20     sum[x]=1;
 21     for(int i=fi[x];i;i=next[i])
 22         if(to[i]!=f)dfs(to[i],x);
 23 }
 24 bool get(int x){
 25     return ch[fa[x]][1]==x;
 26 }
 27 bool isroot(int x){
 28     return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;
 29 }
 30 void update(int x){
 31     int ls=ch[x][0],rs=ch[x][1];
 32     siz[x]=siz[ls]+siz[rs]+1;
 33     sum[x]=(sum[ls]+sum[rs]+v[x])%mod;
 34 }
 35 void pushdown(int x){
 36     int ls=ch[x][0],rs=ch[x][1];
 37     if(rev[x]){
 38         rev[x]=0;
 39         rev[ls]^=1;
 40         rev[rs]^=1;
 41         swap(ch[ls][0],ch[ls][1]);
 42         swap(ch[rs][0],ch[rs][1]);
 43     }
 44     v[x]=(v[x]*mul[x]+add[x])%mod;
 45     mul[ls]=mul[ls]*mul[x]%mod;
 46     mul[rs]=mul[rs]*mul[x]%mod;
 47     add[ls]=(mul[x]*add[ls]+add[x])%mod;
 48     add[rs]=(mul[x]*add[rs]+add[x])%mod;
 49     sum[ls]=(sum[ls]*mul[x]+add[x]*siz[ls])%mod;
 50     sum[rs]=(sum[rs]*mul[x]+add[x]*siz[rs])%mod;
 51     add[x]=0;mul[x]=1;
 52 }
 53 void zig(int x){
 54     int old=fa[x],oldf=fa[old];
 55     pushdown(old);
 56     pushdown(x);
 57     bool p=get(x);
 58     if(!isroot(old))ch[oldf][get(old)]=x;
 59     fa[x]=oldf;
 60     fa[ch[old][p]=ch[x][p^1]]=old;
 61     fa[ch[x][p^1]=old]=x;
 62     update(old);
 63     update(x);
 64 }
 65 void splay(int x){
 66     for(;!isroot(x);zig(x))
 67         if(!isroot(fa[x]))zig(get(x)==get(fa[x])?fa[x]:x);
 68     pushdown(x);//防止单独一个点成splay标记未下传 
 69 }
 70 void access(int x){
 71     int last=0;
 72     while(x){
 73         splay(x);
 74         ch[x][1]=last;
 75         update(x);
 76         last=x;
 77         x=fa[x];
 78     }
 79 }
 80 void makeroot(int x){
 81     access(x);
 82     splay(x);
 83     rev[x]^=1;
 84     swap(ch[x][0],ch[x][1]);
 85 }
 86 void cut(int x,int y){
 87     makeroot(x);
 88     access(y);
 89     splay(y);
 90     ch[y][0]=fa[x]=0;
 91     update(y);
 92 }
 93 void link(int x,int y){
 94     makeroot(x);
 95     fa[x]=y;
 96 }
 97 void Add(int x,int y,int z){
 98     makeroot(x);
 99     access(y);
100     splay(y);
101     add[y]=(add[y]+z)%mod;
102     sum[y]=(sum[y]+z*siz[y])%mod;
103 }
104 void Mul(int x,int y,int z){
105     makeroot(x);
106     access(y);
107     splay(y);
108     add[y]=add[y]*z%mod;
109     mul[y]=mul[y]*z%mod;
110     sum[y]=sum[y]*z%mod;
111 }
112 int Q(int x,int y){
113     makeroot(x);
114     access(y);
115     splay(y);
116     return sum[y];
117 }
118 int main()
119 {
120     scanf("%d%d",&n,&q);
121     for(int i=1;i<n;i++){
122         int x,y;
123         scanf("%d%d",&x,&y);
124         edge_add(x,y);edge_add(y,x);
125     }
126     dfs(1,0);
127     for(int i=1;i<=q;i++){
128         char c;
129         cin>>c;
130         if(c=='+'){
131             int u,v,c;
132             scanf("%d%d%d",&u,&v,&c);
133             Add(u,v,c);
134         }
135         else if(c=='-'){
136             int u1,v1,u2,v2;
137             scanf("%d%d%d%d",&u1,&v1,&u2,&v2);
138             cut(u1,v1);
139             link(u2,v2);
140         }
141         else if(c=='*'){
142             int u,v,c;
143             scanf("%d%d%d",&u,&v,&c);
144             Mul(u,v,c);
145         }
146         else if(c=='/'){
147             int x,y;
148             scanf("%d%d",&x,&y);
149             printf("%d\n",Q(x,y));
150         }
151     }
152     return 0;
153 }
View Code

 

转载于:https://www.cnblogs.com/hyghb/p/8120041.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值