[点分树] BZOJ 4372: 烁烁的游戏

来源:互联网 发布:彩虹6号 淘宝 编辑:程序博客网 时间:2024/06/08 05:49

Description

给一颗n个节点的树,边权均为1,初始点权均为0m次操作:
Q x:询问x的点权。
M x d w:将树上与节点x距离不超过d的节点的点权均加上w

Solution

点分树大裸题。
先把点分树建出来,记录下分治结构上的祖先以及到该祖先的距离。
对每个点以深度为关键字建线段树,维护所管辖的分支结构的信息。
那么修改只要往分治树上爬,在线段树修改就好了。
当然要减掉从当前点走到分治树祖先又走回来的东西。
开两颗线段树就好了。
查询的话直接暴力爬分治树就好啦。

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int INF = 1 << 30;const int B = 100;const int N = 101010;const int M = 30;inline char get(void) {    static char buf[100000], *S = buf, *T = buf;    if (S == T) {        T = (S = buf) + fread(buf, 1, 100000, stdin);        if (S == T) return EOF;    }    return *S++;}template<typename T>inline void read(T &x) {    static char c; x = 0; int sgn = 0;    for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1;    for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';    if (sgn) x = -x;}inline void reado(int &opt) {    static char c;    for (c = get(); c != 'M' && c != 'Q'; c = get());    opt = (c == 'M');}int n, m, x, y, z, Gcnt, Tcnt, opt;struct edge {    int to, next;    edge (int t = 0, int n = 0):to(t), next(n) {}};edge G[N << 1];int head[N];int fa[N][M], dis[N][M];int size[N], vis[N], mxd[N];int root, mn, rt, sum, cnt;int rt1[N], rt2[N], ls[N * B], rs[N * B], t[N * B];inline void AddEdge(int from, int to) {    G[++Gcnt] = edge(to, head[from]); head[from] = Gcnt;    G[++Gcnt] = edge(from, head[to]); head[to] = Gcnt;}inline void Add(int &o, int l, int r, int L, int R, int x) {    if (!o) o = ++Tcnt;    if (l >= L && r <= R) return (void)(t[o] += x);    int mid = (l + r) >> 1;    if (L <= mid) Add(ls[o], l, mid, L, R, x);    if (R > mid) Add(rs[o], mid + 1, r, L, R, x);}inline int Sum(int o, int l, int r, int pos) {    if (l == r || !o) return t[o];    int mid = (l + r) >> 1;    if (pos <= mid) return t[o] + Sum(ls[o], l, mid, pos);    else return t[o] + Sum(rs[o], mid + 1, r, pos);}inline void GetRoot(int u, int f) {    int to, h = 0; size[u] = 1;    for (int i = head[u]; i; i = G[i].next) {        to = G[i].to; if (vis[to] || to == f) continue;        GetRoot(to, u); size[u] += size[to];        h = max(size[to], h);    }    h = max(sum - size[u], h);    if (h < mn) {        root = u; mn = h;    }}inline void dfs(int u, int f, int d) {    int to; ++cnt; mxd[rt] = max(mxd[rt], d);    fa[u][++*fa[u]] = rt; dis[u][++*dis[u]] = d;    for (int i = head[u]; i; i = G[i].next) {        to = G[i].to; if (to == f || vis[to]) continue;        dfs(to, u, d + 1);    }}inline void DivAndConq(int u) {    vis[u] = 1; int to; rt = u; mxd[rt] = 0;    fa[u][++*fa[u]] = rt; dis[u][++*dis[u]] = 0;    for (int i = head[u]; i; i = G[i].next) {        to = G[i].to; if (vis[to]) continue;        cnt = 0; dfs(to, u, 1); size[to] = cnt;    }    for (int i = head[u]; i; i = G[i].next) {        to = G[i].to; if (vis[to]) continue;        mn = INF; sum = size[to];        GetRoot(to, u); DivAndConq(root);    }}inline void Modify(int v, int k, int x) {    int u = v, kk, fu;    Add(rt1[u], 0, mxd[u], 0, min(k, mxd[u]), x);    for (int i = 2; i <= *fa[v]; i++) {        fu = fa[v][i]; kk = k - dis[v][i];        if (kk < 0) {            u = fu; continue;        }        Add(rt2[u], 0, mxd[fu], 0, min(kk, mxd[fu]), -x);        u = fu;        Add(rt1[u], 0, mxd[u], 0, min(kk, mxd[u]), x);    }}inline int Query(int v) {    int ans = 0, u = v, fu;    ans += Sum(rt1[u], 0, mxd[u], 0);    for (int i = 2; i <= *fa[v]; i++) {        fu = fa[v][i];        ans += Sum(rt2[u], 0, mxd[fu], dis[v][i]);        u = fu;        ans += Sum(rt1[u], 0, mxd[u], dis[v][i]);    }    return ans;}inline void Debug(void) {    for (int i = 1; i <= n; i++)        printf("w(%d)%d%c", i, Query(i), i == n ? '\n' : ' ');}int main(void) {    freopen("1.in", "r", stdin);    read(n); read(m);    for (int i = 1; i < n; i++) {        read(x); read(y);        AddEdge(x, y);    }    mn = INF; sum = n;    GetRoot(1, 0); DivAndConq(root);    for (int i = 1; i <= n; i++) {        reverse(fa[i] + 1, fa[i] + *fa[i] + 1);        reverse(dis[i] + 1, dis[i] + *dis[i] + 1);    }    while (m--) {        reado(opt); read(x);        if (opt) {            read(y); read(z);            Modify(x, y, z);        } else {            printf("%d\n", Query(x));        }    }    return 0;}
原创粉丝点击