树链剖分 BZOJ3589 动态树
来源:互联网 发布:ae软件怎么用 编辑:程序博客网 时间:2024/06/16 23:27
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
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 }
阅读全文
0 0
- 树链剖分 BZOJ3589 动态树
- 【bzoj3589】动态树 树链剖分+线段树
- bzoj3589 动态树
- BZOJ3589: 动态树
- [BZOJ3589]动态树(树链剖分+dfs序+lca)
- BZOJ3589动态树,BIT+容斥
- Bzoj3589:动态树:树链剖分+容斥原理+树链的并
- 动态树||树链剖分(BZOJ1036)
- 动态树
- 动态树
- 动态树
- 动态树
- 动态树
- A1517. 动态树 树链剖分+线段树
- 3589: 动态树|树链剖分|线段树
- BZOJ 3589: 动态树 树链剖分线段树
- bzoj 3589: 动态树 树链剖分+线段树
- poj 3237 Tree 树链剖分 动态树 LCT
- 动态规划 BZOJ1296 [SCOI2009]粉刷匠
- 动态规划 BZOJ1710 [Usaco2007 Open]Cheappal 廉价回文
- 最小生成树 BZOJ3714 [PA2014]Kuglarz
- 最大生成树 BZOJ3943 [Usaco2015 Feb]SuperBull
- 二分图 BZOJ4554 [Tjoi2016&Heoi2016]游戏
- 树链剖分 BZOJ3589 动态树
- tarjan强连通分量 洛谷P1262 间谍网络
- 线性DP POJ2279 Mr.Young's Picture Permutations
- 线性DP POJ3666 Making the Grade
- 数位DP POJ3208 Apocalypse Someday
- 线性DP codevs2185 最长公共上升子序列
- 线性DP SPOJ Mobile Service
- 动态规划 BZOJ1925 地精部落
- 分层图最短路(DP思想) BZOJ2662 [BeiJing wc2012]冻结