首页 > 代码库 > 树链剖分 BZOJ3589 动态树

树链剖分 BZOJ3589 动态树

3589: 动态树

Time Limit: 30 Sec  Memory Limit: 1024 MB
Submit: 543  Solved: 193
[Submit][Status][Discuss]

Description

 

别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件
事件0:
这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子.
事件1:
小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次.
 

Input

第一行一个整数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的结果.

Output

对于每个事件1, 输出询问的果子数.

Sample Input

5
1 2
2 3
2 4
1 5
3
0 1 1
0 2 3
1 2 3 1 1 4

Sample Output

13

HINT

 

 1 <= n <= 200,000, 1 <= nQ <= 200,000, K = 5.


生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.

 

Source

By 佚名提供

 
树剖模板题,不过注意只能加一次,所以可以打标记,一次询问后记得清除标记
另外,怎么对1<<31取模不懂
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 int n,m,cnt,tot;
  7 struct dt{
  8     int next,to;
  9 }edge[400010];
 10 struct data{
 11     int father,son,size,top,deep,getin,getout;
 12 }tree[200010];
 13 struct seg{
 14     int sum,tag1,tag2,ret;
 15 }segtree[800010];
 16 int head[200010];
 17 void add(int start,int end){
 18     edge[++cnt].next=head[start];
 19     edge[cnt].to=end;
 20     head[start]=cnt;
 21 }
 22 void dfs_weight(int u){
 23     tree[u].size=1;
 24     tree[u].son=0;
 25     for(int i=head[u];i;i=edge[i].next)
 26         if(edge[i].to!=tree[u].father){
 27             tree[edge[i].to].deep=tree[u].deep+1;
 28             tree[edge[i].to].father=u;
 29             dfs_weight(edge[i].to);
 30             tree[u].size+=tree[edge[i].to].size;
 31             if(tree[edge[i].to].size>tree[tree[u].son].size) tree[u].son=edge[i].to; 
 32         }
 33 }
 34 void dfs_build(int u,int tp){
 35     tree[u].getin=++tot;
 36     tree[u].top=tp;
 37     if(tree[u].son){
 38         dfs_build(tree[u].son,tp);
 39         for(int i=head[u];i;i=edge[i].next)
 40             if(edge[i].to!=tree[u].son&&edge[i].to!=tree[u].father) dfs_build(edge[i].to,edge[i].to); 
 41     }
 42     tree[u].getout=tot;
 43 }
 44 void up(int pos){
 45     segtree[pos].sum=segtree[pos<<1].sum+segtree[pos<<1|1].sum;
 46     segtree[pos].ret=segtree[pos<<1].ret+segtree[pos<<1|1].ret;
 47 }
 48 void update1(int pos,int d){
 49     segtree[pos].tag1=d;
 50     segtree[pos].ret=segtree[pos].sum*d;
 51 }
 52 void update2(int pos,int d,int ll,int rr){
 53     segtree[pos].tag2+=d;
 54     segtree[pos].sum+=(rr-ll+1)*d;
 55 }
 56 void down(int pos,int ll,int mid,int rr){
 57     if(segtree[pos].tag2){
 58         update2(pos<<1,segtree[pos].tag2,ll,mid);
 59         update2(pos<<1|1,segtree[pos].tag2,mid+1,rr);
 60         segtree[pos].tag2=0;
 61     }
 62     if(segtree[pos].tag1!=-1){
 63         update1(pos<<1,segtree[pos].tag1);
 64         update1(pos<<1|1,segtree[pos].tag1);
 65         segtree[pos].tag1=-1;
 66     }
 67 }
 68 void build(int pos,int ll,int rr){
 69     if(ll==rr){
 70         segtree[pos].tag1=-1;
 71         return;
 72     }
 73     int mid=(ll+rr)>>1;
 74     build(pos<<1,ll,mid);
 75     build(pos<<1|1,mid+1,rr);
 76 }
 77 void change(int pl,int pr,int d,int pos,int ll,int rr){
 78     if(pl>rr||pr<ll) return;
 79     if(segtree[pos].tag1==d) return;    
 80     if(pl<=ll&&pr>=rr){
 81         update1(pos,d);
 82         return;
 83     }
 84     int mid=(ll+rr)>>1;
 85     down(pos,ll,mid,rr);
 86     if(pr<=mid) change(pl,pr,d,pos<<1,ll,mid);
 87     else if(pl>mid) change(pl,pr,d,pos<<1|1,mid+1,rr);
 88     else{
 89         change(pl,mid,d,pos<<1,ll,mid);
 90         change(mid+1,pr,d,pos<<1|1,mid+1,rr);
 91     }
 92     up(pos);
 93 }
 94 void ask_some(int aa,int bb){
 95     int t1=tree[aa].top;
 96     int t2=tree[bb].top;
 97     while(t1!=t2){
 98         if(tree[t1].deep<tree[t2].deep){
 99             change(tree[t2].getin,tree[bb].getin,1,1,1,n);
100             bb=tree[t2].father;
101             t2=tree[bb].top;
102         }
103         else{
104             change(tree[t1].getin,tree[aa].getin,1,1,1,n);
105             aa=tree[t1].father;
106             t1=tree[aa].top;
107         }
108     }
109     if(tree[aa].deep<tree[bb].deep) change(tree[aa].getin,tree[bb].getin,1,1,1,n);
110     else change(tree[bb].getin,tree[aa].getin,1,1,1,n);
111 }
112 void add_val(int pl,int pr,int d,int pos,int ll,int rr){
113     if(pl>rr||pr<ll) return;
114     if(pl<=ll&&pr>=rr){
115         update2(pos,d,ll,rr);
116         return;
117     }
118     int mid=(ll+rr)>>1;
119     down(pos,ll,mid,rr);
120     if(pr<=mid) add_val(pl,pr,d,pos<<1,ll,mid);
121     else if(pl>mid) add_val(pl,pr,d,pos<<1|1,mid+1,rr);
122     else{
123         add_val(pl,mid,d,pos<<1,ll,mid);
124         add_val(mid+1,pr,d,pos<<1|1,mid+1,rr);
125     }
126     up(pos);
127 }
128 int main(){
129     scanf("%d",&n);
130     int x=0,y=0;
131     for(int i=1;i<n;i++){
132         scanf("%d%d",&x,&y);
133         add(x,y);
134         add(y,x);
135     }
136     tree[1].deep=1;
137     dfs_weight(1);
138     dfs_build(1,1);
139     build(1,1,n);
140     scanf("%d",&m);
141     int od=0,k=0;
142     for(int i=1;i<=m;i++){
143         scanf("%d",&od);
144         if(od){
145             scanf("%d",&k);
146             for(int j=1;j<=k;j++){
147                 scanf("%d%d",&x,&y);
148                 ask_some(x,y);
149             }
150             printf("%d\n",segtree[1].ret&((1<<31)-1));//???编译显示溢出 
151             update1(1,0);
152         }
153         else{
154             scanf("%d%d",&x,&y);
155             add_val(tree[x].getin,tree[x].getout,y,1,1,n);
156         } 
157     }
158     return 0;
159 }

 

树链剖分 BZOJ3589 动态树