【题目链接】
【思路要点】
- 维护一个糖果集合,支持加入一个糖果,删除一个糖果,显然,我们可以容易地在\(O(1)\)的时间内实现这些操作。
- 考虑使用莫队算法。对树分块,运行树上带修莫队即可。
- 实际上,这是一道树上带修莫队的模板题,相当于将带修莫队、树上莫队和树分块合为一体。
- 时间复杂度\(O(N^{\frac{5}{3}})\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 100005 #define SIZE 2100 #define MAXLOG 20 template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } struct querys {int x, y, lca, timer, home; } b[MAXN]; struct changes {int pos, val; } c[MAXN]; vector <int> a[MAXN]; int father[MAXN][MAXLOG], depth[MAXN]; int num[MAXN], tot; int stk[MAXN], top; int n, m, q, qb, qc, nowc; long long ans[MAXN], nowans; long long vm[MAXN], vn[MAXN]; int col[MAXN], now[MAXN], cnt[MAXN]; bool exist[MAXN]; int lca(int x, int y) { if (depth[x] < depth[y]) swap(x, y); for (int i = MAXLOG - 1; i >= 0; i--) if (depth[father[x][i]] >= depth[y]) x = father[x][i]; if (x == y) return x; for (int i = MAXLOG - 1; i >= 0; i--) if (father[x][i] != father[y][i]) { x = father[x][i]; y = father[y][i]; } return father[x][0]; } void add(int type) { cnt[type]++; nowans += vn[cnt[type]] * vm[type]; } void dec(int type) { nowans -= vn[cnt[type]] * vm[type]; cnt[type]--; } void Xor(int x, int fa) { while (x != fa) { if (exist[x]) { exist[x] = false; dec(now[x]); } else { exist[x] = true; add(now[x]); } x = father[x][0]; } } void move(int x, int y) { int Lca = lca(x, y); Xor(x, Lca), Xor(y, Lca); } void modify(int x, int y) { if (!exist[x]) { now[x] = y; return; } dec(now[x]); now[x] = y; add(now[x]); } void process(int l, int r) { for (int i = 1; i <= n; i++) now[i] = col[i]; memset(cnt, 0, sizeof(cnt)); memset(exist, false, sizeof(exist)); nowans = nowc = 0; while (nowc < b[l].timer) { nowc++; modify(c[nowc].pos, c[nowc].val); } move(b[l].x, b[l].y); add(now[b[l].lca]); ans[b[l].home] = nowans; dec(now[b[l].lca]); for (int i = l + 1; i <= r; i++) { while (nowc < b[i].timer) { nowc++; modify(c[nowc].pos, c[nowc].val); } move(b[i].x, b[i - 1].x); move(b[i].y, b[i - 1].y); add(now[b[i].lca]); ans[b[i].home] = nowans; dec(now[b[i].lca]); } } void work(int pos, int fa, int start) { father[pos][0] = fa; depth[pos] = depth[fa] + 1; for (int i = 1; i < MAXLOG; i++) father[pos][i] = father[father[pos][i - 1]][i - 1]; for (unsigned i = 0; i < a[pos].size(); i++) { if (a[pos][i] == fa) continue; work(a[pos][i], pos, top); if (top - start >= SIZE) { tot++; for (int i = start + 1; i <= top; i++) num[stk[i]] = tot; top = start; } } stk[++top] = pos; if (top - start >= SIZE) { tot++; for (int i = start + 1; i <= top; i++) num[stk[i]] = tot; top = start; } } bool cmp(querys a, querys b) { if (num[a.x] == num[b.x]) { if (num[a.y] == num[b.y]) return a.timer < b.timer; else return num[a.y] < num[b.y]; } else return num[a.x] < num[b.x]; } int main() { read(n), read(m), read(q); for (int i = 1; i <= m; i++) read(vm[i]); for (int i = 1; i <= n; i++) read(vn[i]); for (int i = 1; i <= n - 1; i++) { int x, y; read(x), read(y); a[x].push_back(y); a[y].push_back(x); } for (int i = 1; i <= n; i++) read(col[i]); work(1, 0, 0); if (top) { tot++; for (int i = 1; i <= top; i++) num[stk[i]] = tot; top = 0; } for (int i = 1; i <= q; i++) { int opt, x, y; read(opt), read(x), read(y); if (opt == 0) c[++qc] = (changes) {x, y}; else { if (num[x] > num[y]) swap(x, y); b[++qb] = (querys) {x, y, lca(x, y), qc, qb}; } } sort(b + 1, b + qb + 1, cmp); int last = 0; for (int i = 1; i <= qb; i++) if (num[b[i].x] != num[b[i + 1].x] || num[b[i].y] != num[b[i + 1].y]) { process(last + 1, i); last = i; } for (int i = 1; i <= qb; i++) printf("%lld\n", ans[i]); return 0; }