【BZOJ 3589】 动态树
2017-04-26 17:07
369 查看
思路
维护点到跟的路径的权值和,记录二元组(a,b)来处理子树加的情况,多条路径的信息合并时,枚举每一条边与其他边的相交的情况,求LCA分类讨论即可。时间复杂度:O(k2×qlogn)
代码
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; typedef unsigned int uint; const int maxn = 200010; const uint mod = (1u<<31)-1; int n, m; uint head[maxn], to[maxn<<1], nxt[maxn<<1], cnt; uint top[maxn], dep[maxn], fa[maxn], son[maxn], st[maxn], tp; uint num[maxn], pos[maxn], tim, q[maxn], sz[maxn]; void add(int a, int b){nxt[++ cnt] = head[a], to[head[a] = cnt] = b;} #define mid ((l+r)>>1) #define lch ((now<<1)) #define rch ((now<<1)|1) struct node{ uint x, y, tg1, tg2; node(uint a = 0, uint b = 0){x = a, y = b, tg1 = 0, tg2 = 0;} void update(uint a, uint b){x += a, y += b, tg1 += a, tg2 += b;} void down(); }T[maxn*3]; void node::down(){ uint now = (this - T); T[lch].update(tg1, tg2); T[rch].update(tg1, tg2); tg1 = 0, tg2 = 0; } void pre(){ uint l = 1, r = 0; tp = 0; q[++ r] = 1, dep[1] = 1; while(l <= r){ uint x = q[l ++]; sz[x] = 1; for(int i = head[x]; i; i = nxt[i]){ uint u = to[i]; if(u == fa[x]) continue; dep[u] = dep[x] + 1, fa[u] = x, q[++ r] = u; } } for(int i = n; i >= 1; i --){ uint x = q[i]; if(!fa[x]) continue; sz[fa[x]] += sz[x]; if(sz[son[fa[x]]] < sz[x]) son[fa[x]] = x; } st[++ tp] = 1, top[1] = 1; while(tp){ uint x = st[tp --]; pos[x] = ++ tim, num[tim] = x; for(int i = head[x]; i; i = nxt[i]){ uint u = to[i]; if(u == fa[x] || u == son[x]) continue; st[++ tp] = u, top[u] = u; } if(son[x]) st[++ tp] = son[x], top[son[x]] = top[x]; } } int lca(int x, int y){ while(top[x] != top[y]){ if(dep[top[x]] < dep[top[y]]) y = fa[top[y]]; else x = fa[top[x]]; } return dep[x] < dep[y] ? x : y; } void modify(int now, int l, int r, int pos1, int pos2, uint a, uint b){ if(l == pos1 && r == pos2){T[now].update(a, b); return;}T[now].down(); if(pos2 <= mid) modify(lch, l, mid, pos1, pos2, a, b); else if(pos1 >= mid+1) modify(rch, mid+1, r, pos1, pos2, a, b); else modify(lch, l, mid, pos1, mid, a, b), modify(rch, mid+1, r, mid+1, pos2, a, b); } uint que(int now, int l, int r, int pos){ if(l == r) return T[now].x*dep[num[l]] + T[now].y; T[now].down(); if(pos <= mid) re dccd turn que(lch, l, mid, pos); else return que(rch, mid+1, r, pos); } struct point{int x, y;}; inline int gt(){ char _ch; int _num = 0, _ok = 0; while(1){ _ch = getchar(); if(_ch >= '0' && _ch <= '9') _num = _num*10 + _ch - '0', _ok = 1; else if(_ok) return _num; } } int main(){ scanf("%d", &n); for(int i = 1, a, b; i < n; i ++){ a = gt(), b = gt(); add(a, b), add(b, a); } pre(); scanf("%d", &m); for(int t = 1; t <= m; t ++){ int op = gt(), x, y; if(op == 0){ x = gt(), y = gt(); modify(1, 1, n, pos[x], pos[x]+sz[x]-1, y, uint(-y * (dep[x]-1))); }else{ int k = gt(); uint sum = 0; point p[6]; for(int i = 1; i <= k; i ++){ p[i].x = gt(), p[i].y = gt(); if(dep[p[i].x] < dep[p[i].y]) swap(p[i].x, p[i].y); p[i].y = fa[p[i].y]; } for(int i = 1; i <= k; i ++){ for(int j = 1; j < i; j ++){ int lca1 = lca(p[i].x, p[j].x); if(dep[lca1] >= dep[p[i].y] + 1 && dep[lca1] >= dep[p[j].y] + 1){ if(dep[p[i].y] > dep[p[j].y]) p[i].y = p[j].y; p[j].y = lca1; } } } for(int i = 1; i <= k; i ++){ sum += que(1, 1, n, pos[p[i].x]); if(p[i].y != 0) sum -= que(1, 1, n, pos[p[i].y]); } printf("%u\n", (sum & mod)); } } return 0; }
相关文章推荐
- bzoj3589 动态树
- bzoj3589 动态树
- bzoj3589 动态树
- 树链剖分 BZOJ3589 动态树
- 【bzoj3589】动态树 树链剖分+线段树
- BZOJ 3589 动态树 树链拆分+纳入和排除定理
- BZOJ3589 : 动态树
- bzoj千题计划214:bzoj3589: 动态树
- BZOJ 3589 动态树
- BZOJ 3589 动态树 树链剖分+容斥定理
- 【BZOJ】3589 动态树 树链剖分+线段树
- [BZOJ3589]动态树(树链剖分)
- bzoj3589 动态树
- [BZOJ3589]动态树(树链剖分+dfs序+lca)
- BZOJ3589: 动态树
- bzoj 3589 动态树
- BZOJ 3589 动态树 树链剖分+容斥原理
- 【BZOJ3589】动态树 树链剖分+线段树
- BZOJ 3589 动态树(子树操作,链查询)
- BZOJ 3589: 动态树 树链剖分线段树