题目 : http://www.tsinsen.com/A1517
A1517. 动态树
时间限制:3.0s 内存限制:1.0GB
总提交次数:227 AC次数:67 平均分:49.52
将本题分享到:
试题来源
中国国家队清华集训 2013-2014 第四天
问题描述
小明在楼下种了一棵动态树, 该树每天会在某些节点上长出一些果子. 这棵树的根节点为1, 它有n个节点, n-1条边.
别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件
事件0:
这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子.
事件1:
小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次.
初始时, 每个节点上都没有果子.
输入格式
第一行一个整数n(1<=n<=200,000), 即节点数.
接下来n-1行, 每行两个数字u, v. 表示果子u和果子v之间有一条直接的边. 节点从1开始编号.
在接下来一个整数nQ(1<=nQ<=200,000), 表示事件.
最后nQ行, 每行开头要么是0, 要么是1.
如果是0, 表示这个事件是事件0. 这行接下来的2个整数u, delta表示以u为根的子树中的每个节点长出了delta个果子.
如果是1, 表示这个事件是事件1. 这行接下来一个整数K(1<=K<=5), 表示这次询问涉及K个树枝. 接下来K对整数u_k, v_k, 每个树枝从节点u_k到节点v_k. 由于果子数可能非常多, 请输出这个数模2^31的结果.
输出格式
对于每个事件1, 输出询问的果子数.
样例输入
5
1 2
2 3
2 4
1 5
3
0 1 1
0 2 3
1 2 3 1 1 4
样例输出
13
数据规模和约定
对于测试点1, 有1 <= n <= 2,000, 1 <= nQ <= 2,000, K <=5
对于测试点{2, 3}, 有1 <= n <= 100,000, 1 <= nQ <= 100,000, K = 1
对于测试点{4, 5}, 有1 <= n <= 100,000, 1 <= nQ <= 100,000, K <= 2
对于测试点{6, 7}, 有1 <= n <= 100,000, 1 <= nQ <= 100,000, K <= 3
对于测试点{8, 9, 10}, 有1 <= n <= 200,000, 1 <= nQ <= 200,000, K = 5.
同一组类型的数据有梯度.
生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.
题解:
树链剖分+线段树+子树操作
修改时将链上的点打标记(注意:初始时这个标记要赋为 -1 ,不能赋为 0 ,因为 0 在之后的操作中要用。)然后查询时,将链上的标记的值相加,边加边取余。(好像可以自然溢出,因为给的数为2^31)
每次询问完要将标记清空。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define MOD 2147483648LL 4 #define MAXN 200010 5 #define LL long long 6 struct NODE 7 { 8 int begin,end,next; 9 }edge[MAXN*2]; 10 struct node 11 { 12 int left,right; 13 LL sum,tag,tag1,prey; 14 }tree[MAXN*4]; 15 int cnt,Head[MAXN],n,deep[MAXN],size[MAXN],P[MAXN][18],pos[MAXN],belong[MAXN],ks[MAXN],js[MAXN],SIZE; 16 bool vis[MAXN]; 17 void addedge(int bb,int ee) 18 { 19 edge[++cnt].begin=bb;edge[cnt].end=ee;edge[cnt].next=Head[bb];Head[bb]=cnt; 20 } 21 void addedge1(int bb,int ee) 22 { 23 addedge(bb,ee);addedge(ee,bb); 24 } 25 int read() 26 { 27 int s=0,fh=1;char ch=getchar(); 28 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)fh=-1;ch=getchar();} 29 while(ch>=‘0‘&&ch<=‘9‘){s=s*10+(ch-‘0‘);ch=getchar();} 30 return s*fh; 31 } 32 void dfs1(int u) 33 { 34 int i,v; 35 size[u]=1;vis[u]=true; 36 for(i=Head[u];i!=-1;i=edge[i].next) 37 { 38 v=edge[i].end; 39 if(vis[v]==false) 40 { 41 deep[v]=deep[u]+1; 42 P[v][0]=u; 43 dfs1(v); 44 size[u]+=size[v]; 45 } 46 } 47 } 48 void Ycl() 49 { 50 int i,j; 51 for(j=1;(1<<j)<=n;j++) 52 { 53 for(i=1;i<=n;i++) 54 { 55 if(P[i][j-1]!=-1)P[i][j]=P[P[i][j-1]][j-1]; 56 } 57 } 58 } 59 void dfs2(int u,int chain) 60 { 61 int k=0,i,v; 62 pos[u]=++SIZE;belong[u]=chain;ks[u]=SIZE; 63 for(i=Head[u];i!=-1;i=edge[i].next) 64 { 65 v=edge[i].end; 66 if(deep[v]>deep[u]&&size[v]>size[k])k=v; 67 } 68 if(k==0){js[u]=SIZE;return;} 69 dfs2(k,chain); 70 for(i=Head[u];i!=-1;i=edge[i].next) 71 { 72 v=edge[i].end; 73 if(deep[v]>deep[u]&&v!=k)dfs2(v,v); 74 } 75 js[u]=SIZE; 76 } 77 void Pushup(int k) 78 { 79 tree[k].sum=(tree[k*2].sum+tree[k*2+1].sum)%MOD; 80 tree[k].prey=(tree[k*2].prey+tree[k*2+1].prey)%MOD; 81 } 82 void Build(int k,int l,int r) 83 { 84 tree[k].left=l;tree[k].right=r;tree[k].tag=-1;/*一定要赋为-1*/tree[k].tag1=0LL;tree[k].sum=0LL; 85 if(l==r)return; 86 int mid=(l+r)/2; 87 Build(k*2,l,mid);Build(k*2+1,mid+1,r); 88 Pushup(k); 89 } 90 void Update(int k,int k1) 91 { 92 tree[k].tag=(LL)k1; 93 tree[k].prey=(tree[k].sum*(LL)k1)%MOD; 94 } 95 void Update1(int k,int k1) 96 { 97 tree[k].tag1=(tree[k].tag1+(LL)k1)%MOD; 98 tree[k].sum=(tree[k].sum+((LL)tree[k].right-(LL)tree[k].left+1LL)*(LL)k1)%MOD; 99 } 100 void Pushdown(int k) 101 { 102 int l=k*2,r=k*2+1; 103 if(tree[k].tag1!=0LL) 104 { 105 Update1(l,tree[k].tag1); 106 Update1(r,tree[k].tag1); 107 tree[k].tag1=0LL; 108 } 109 if(tree[k].tag!=-1) 110 { 111 Update(l,tree[k].tag); 112 Update(r,tree[k].tag); 113 tree[k].tag=-1; 114 } 115 } 116 void Add(int k,int l,int r,int A) 117 { 118 if(l==tree[k].left&&tree[k].right==r){Update1(k,A);return;} 119 int mid=(tree[k].left+tree[k].right)/2; 120 Pushdown(k); 121 if(r<=mid)Add(k*2,l,r,A); 122 else if(l>mid)Add(k*2+1,l,r,A); 123 else {Add(k*2,l,mid,A);Add(k*2+1,mid+1,r,A);} 124 Pushup(k); 125 } 126 void Change(int k,int l,int r,int C) 127 { 128 if(tree[k].tag==C)return; 129 if(l==tree[k].left&&tree[k].right==r){Update(k,C);return;} 130 int mid=(tree[k].left+tree[k].right)/2; 131 Pushdown(k); 132 if(r<=mid)Change(k*2,l,r,C); 133 else if(l>mid)Change(k*2+1,l,r,C); 134 else {Change(k*2,l,mid,C);Change(k*2+1,mid+1,r,C);} 135 Pushup(k); 136 } 137 void Solve_change(int x,int fa,int C) 138 { 139 while(belong[x]!=belong[fa]) 140 { 141 //if(deep[belong[x]]<deep[belong[fa]])swap(x,fa); 142 Change(1,pos[belong[x]],pos[x],C); 143 x=P[belong[x]][0]; 144 } 145 //if(deep[x]<deep[fa])swap(x,fa); 146 Change(1,pos[fa],pos[x],C); 147 } 148 int main() 149 { 150 int bb,ee,Q,i,zs,s1,s2,s3,j; 151 n=read(); 152 memset(Head,-1,sizeof(Head));cnt=1; 153 for(i=1;i<n;i++){bb=read();ee=read();addedge1(bb,ee);} 154 memset(P,-1,sizeof(P));SIZE=0; 155 dfs1(1);Ycl(); 156 dfs2(1,1); 157 Q=read(); 158 Build(1,1,n); 159 for(i=1;i<=Q;i++) 160 { 161 zs=read(); 162 if(zs==0){s1=read();s2=read();Add(1,ks[s1],js[s1],s2);} 163 else 164 { 165 s1=read(); 166 for(j=1;j<=s1;j++) 167 { 168 s2=read();s3=read(); 169 if(deep[s2]<deep[s3])swap(s2,s3); 170 Solve_change(s2,s3,1); 171 //printf("%d\n",tree[1].prey); 172 //Update(1,0); 173 } 174 printf("%lld\n",tree[1].prey%MOD); 175 Update(1,0); 176 } 177 } 178 fclose(stdin); 179 fclose(stdout); 180 return 0; 181 }