1. 程式人生 > >樹鏈剖分 BZOJ3589 動態樹

樹鏈剖分 BZOJ3589 動態樹

ext 個數字 ret mst sin 2個 tput spa mit

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 動態樹