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

## Description$Description$

Q x$Q~x$：询问x$x$的点权。
M x d w$M~x~d~w$：将树上与节点x$x$距离不超过d$d$的节点的点权均加上w$w$

## Solution$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>
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;
}
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 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) {
}
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);
for (int i = 1; i < n; i++) {
}
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--) {
if (opt) {
Modify(x, y, z);
} else {
printf("%d\n", Query(x));
}
}
return 0;
}

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客