树链剖分 BZOJ3589 动态树
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链剖分 BZOJ3589 动态树相关的知识,希望对你有一定的参考价值。
3589: 动态树
Time Limit: 30 Sec Memory Limit: 1024 MBSubmit: 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
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
树剖模板题,不过注意只能加一次,所以可以打标记,一次询问后记得清除标记
另外,怎么对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 动态树的主要内容,如果未能解决你的问题,请参考以下文章