您的位置:首页 > 其它

【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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: