Description
Input
Output
Sample Input
4 3 1 1 1 1 1 2 2 3 3 4 ? 2 1 ! 1 0 ? 2 1 3 3 1 2 3 1 2 1 3 ? 1 0 ? 1 1 ? 1 2
Sample Output
3 2 1 6 6
动态树分治,每个节点维护两个树状数组,以及一个记录距离的数组。
#include<map> #include<vector> #include<cstdio> #include<algorithm> using namespace std; typedef long long LL; const int low(int x) { return x&-x; } const int maxn = 3e5 + 10; const int INF = 0x7FFFFFFF; int N, Q, w[maxn], x, y; char ch[5]; struct Tree { int ft[maxn], nt[maxn], u[maxn], sz; int mx[maxn], ct[maxn], vis[maxn]; int pre[maxn]; struct point { int x, y; point(int x = 0, int y = 0) :x(x), y(y) {} bool operator<(const point &a)const { return x < a.x; } }; vector<int> d[maxn], D[maxn]; vector<point> dis[maxn]; void clear(int n) { mx[sz = 0] = INF; for (int i = 1; i <= n; i++) { ft[i] = -1, vis[i] = 0; d[i].clear(), D[i].clear(); dis[i].clear(); } } void AddEdge(int x, int y) { u[sz] = y; nt[sz] = ft[x]; ft[x] = sz++; u[sz] = x; nt[sz] = ft[y]; ft[y] = sz++; } int dfs(int x, int fa, int sum) { int y = mx[x] = (ct[x] = 1) - 1; for (int i = ft[x]; i != -1; i = nt[i]) { if (u[i] == fa || vis[u[i]]) continue; int z = dfs(u[i], x, sum); ct[x] += ct[u[i]]; mx[x] = max(mx[x], ct[u[i]]); y = mx[y] < mx[z] ? y : z; } mx[x] = max(mx[x], sum - ct[x]); return mx[x] < mx[y] ? x : y; } int getdep(int x, int fa, int dep, int rt) { if (rt) dis[rt].push_back(point(x, dep)); int ans = dep; for (int i = ft[x]; i != -1; i = nt[i]) { if (u[i] == fa || vis[u[i]]) continue; ans = max(getdep(u[i], x, dep + 1, rt), ans); } return ans; } void put(int x, int fa, int dep, vector<int> &p) { if (dep) { for (int i = dep; i < p.size(); i += low(i)) p[i] += w[x]; } for (int i = ft[x]; i != -1; i = nt[i]) { if (u[i] == fa || vis[u[i]]) continue; put(u[i], x, dep + 1, p); } } int build(int x, int sum, int fa) { int y = dfs(x, -1, sum); pre[y] = fa; vis[y] = 1; int len = getdep(y, -1, 0, y); sort(dis[y].begin(), dis[y].end()); for (int i = 0; i <= len; i++) d[y].push_back(0); put(y, -1, 0, d[y]); for (int i = ft[y]; i != -1; i = nt[i]) { if (vis[u[i]]) continue; int z = build(u[i], ct[u[i]] > ct[y] ? sum - ct[y] : ct[u[i]], y); len = getdep(u[i], y, 1, 0); for (int j = 0; j <= len; j++) D[z].push_back(0); put(u[i], y, 1, D[z]); } vis[y] = 0; return y; } int work(int rt, int x, int y) { int ans = 0; if (x == rt) { for (int i = min(y, (int)d[rt].size() - 1); i; i -= low(i)) ans += d[rt][i]; ans += w[x]; } if (pre[x] != -1) { int k = dis[pre[x]][lower_bound(dis[pre[x]].begin(), dis[pre[x]].end(), point(rt, 0)) - dis[pre[x]].begin()].y; if (k <= y) { ans += w[pre[x]]; for (int i = min(y - k, (int)d[pre[x]].size() - 1); i; i -= low(i)) ans += d[pre[x]][i]; for (int i = min(y - k, (int)D[x].size() - 1); i; i -= low(i)) ans -= D[x][i]; } ans += work(rt, pre[x], y); } return ans; } void change(int rt, int x, int y) { if (pre[x] == -1) return; int k = dis[pre[x]][lower_bound(dis[pre[x]].begin(), dis[pre[x]].end(), point(rt, 0)) - dis[pre[x]].begin()].y; for (int i = k; i < d[pre[x]].size(); i += low(i)) d[pre[x]][i] += y; for (int i = k; i < D[x].size(); i += low(i)) D[x][i] += y; change(rt, pre[x], y); } }solve; int main() { while (scanf("%d%d", &N, &Q) != EOF) { solve.clear(N); for (int i = 1; i <= N; i++) scanf("%d", &w[i]); for (int i = 1; i < N; i++) { scanf("%d%d", &x, &y); solve.AddEdge(x, y); } solve.build(1, N, -1); while (Q--) { scanf("%s%d%d", ch, &x, &y); if (ch[0] == '?') printf("%d\n", solve.work(x, x, y)); else { solve.change(x, x, y - w[x]); w[x] = y; } } } return 0; }