BZOJ 3589: 动态树 树链剖分线段树
2017-05-18 16:53
369 查看
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.
生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.
解法:树链剖分,线段树维护。为何第一次写的代码一直挂,推了重写了就过了。
别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件
事件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.
生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.
解法:树链剖分,线段树维护。为何第一次写的代码一直挂,推了重写了就过了。
///BZOJ 2589 #include <bits/stdc++.h> using namespace std; const int maxn = 200010; struct edge{int v,next;}E[maxn*2]; struct seg{int l,r,sum,tag[2],ret;}tree[maxn*4]; int n, m, x, y, cnt, tim, op, l[maxn], r[maxn], dep[maxn]; int fa[maxn], siz[maxn], son[maxn], head[maxn], top[maxn]; void init(){ memset(head, -1, sizeof(head)); memset(son, -1, sizeof(son)); tim=cnt=0; } void add(int u, int v){ E[cnt].v=v,E[cnt].next=head[u],head[u]=cnt++; } void dfs1(int u, int father, int d){ dep[u]=d; fa[u]=father; siz[u]=1; for(int i=head[u];~i;i=E[i].next){ int v=E[i].v; if(v==father) continue; dfs1(v,u,d+1); siz[u]+=siz[v]; if(son[u]==-1||siz[v]>siz[son[u]]) son[u]=v; } } void dfs2(int u, int tp){ top[u]=tp; l[u]=++tim; r[u]=tim; if(son[u]==-1) return; dfs2(son[u],tp); for(int i=head[u];~i;i=E[i].next){ int v=E[i].v; if(v!=son[u]&&v!=fa[u]) dfs2(v,v); } r[u]=tim; } void pushup(int rt){ tree[rt].sum=tree[rt*2].sum+tree[rt*2+1].sum; tree[rt].ret=tree[rt*2].ret+tree[rt*2+1].ret; } void build(int l, int r, int rt){ tree[rt].l=l,tree[rt].r=r,tree[rt].tag[0]=-1; if(l==r) return; int mid=(l+r)/2; build(l,mid,rt*2); build(mid+1,r,rt*2+1); } void update1(int rt, int z){ tree[rt].tag[1]+=z; tree[rt].sum+=z*(tree[rt].r-tree[rt].l+1); } void update2(int rt, int z){ tree[rt].tag[0]=z; tree[rt].ret=tree[rt].sum*z; } void pushdown(int rt){ if(tree[rt].tag[1]){ update1(rt*2,tree[rt].tag[1]); update1(rt*2+1,tree[rt].tag[1]); tree[rt].tag[1]=0; } if(tree[rt].tag[0]!=-1){ update2(rt*2,tree[rt].tag[0]); update2(rt*2+1,tree[rt].tag[0]); tree[rt].tag[0]=-1; } } void change(int x, int y, int z, int rt){ if(tree[rt].tag[0]==z) return; if(tree[rt].l==x&&tree[rt].r==y){update2(rt,z);return;} int mid=(tree[rt].l+tree[rt].r)/2; pushdown(rt); if(y<=mid) change(x,y,z,rt*2); else if(x>mid) change(x,y,z,rt*2+1); else{ change(x,mid,z,rt*2); change(mid+1,y,z,rt*2+1); } pushup(rt); } void add(int x, int y, int z, int rt){ if(tree[rt].l==x&&tree[rt].r==y){update1(rt,z);return;} int mid=(tree[rt].l+tree[rt].r)/2; pushdown(rt); if(y<=mid) add(x,y,z,rt*2); else if(x>mid) add(x,y,z,rt*2+1); else{ add(x,mid,z,rt*2); add(mid+1,y,z,rt*2+1); } pushup(rt); } void solve(int x, int y, int z){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); change(l[top[x]],l[x],z,1); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); change(l[x],l[y],z,1); } int main(){ scanf("%d", &n); init(); for(int i=1; i<n; i++){ int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs1(1,1,1); dfs2(1,1); build(1,n,1); scanf("%d", &m); while(m--){ int op,x,u,v; scanf("%d%d",&op,&x); if(op){ for(int i=1; i<=x; i++){ scanf("%d%d", &u,&v); solve(u,v,1); } printf("%d\n", tree[1].ret&((1<<31)-1)); update2(1,0); } else{ scanf("%d", &u); add(l[x],r[x],u,1); } } return 0; }
相关文章推荐
- bzoj 3531(动态加点线段树,树链剖分)
- BZOJ 3531 旅行 (树链剖分 + 线段树动态开点)
- BZOJ 3531 (树链剖分,线段树动态开点)
- 【bzoj3589】动态树 树链剖分+线段树
- 3589: 动态树|树链剖分|线段树
- |BZOJ 3531|树链剖分|动态开点线段树|[Sdoi2014]旅行
- BZOJ 3589 动态树(子树操作,链查询)
- 【bzoj3531】 [SDOI2014]旅行 树链剖分+动态开点线段树
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
- [bzoj4196][Noi2015]软件包管理器_树链剖分_线段树
- bzoj 3683: Falsita 树链剖分+线段树
- |BZOJ 4034|树链剖分|线段树|[HAOI2015]树上操作
- bzoj 2402 陶陶的难题II 01分数规划 树链剖分 线段树维护凸包
- [bzoj4515][Sdoi2016]游戏-树链剖分+李超线段树
- BZOJ 4034 树上操作 (树链剖分 线段树)
- [树链剖分 线段树 标记永久化] BZOJ 4515 [Sdoi2016]游戏
- BZOJ-4034: [HAOI2015]树上操作 (树链剖分 入门题 子树整体修改 线段树 区间修改+查询)
- bzoj2243 染色 树链剖分 线段树
- 【BZOJ3531】旅行,树链剖分+开点线段树
- 【BZOJ4034】[HAOI2015]T2【树链剖分】【线段树】