84
题目大意:给定一棵树,每个点有一个颜色,提供两种操作: 1.询问两点间路径上的Σv[a[i]]*w[k],其中a[i]代表这个点的颜色,k表示这个点是这种颜色第k次出现 2.修改某个点的颜色
带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之后为第三关键字 排序。
该题参考http://blog.csdn.net/qzh_1430586275/article/details/51434506
#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; const int maxn = 100100; typedef long long ll; inline int read() { char ch = getchar(); int x = 0, f = 1; while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while ('0' <= ch && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } struct Edge { int en, next; } E[maxn * 2]; int head[maxn], num; int first[maxn]; int n, m, q; int v[maxn], w[maxn], col[maxn], cnt[maxn]; int tid[maxn], st[maxn], stn, dep[maxn], fa[maxn][20], BLOCKSIZE, blockclk; bool in[maxn]; ll ansnow, ans[maxn]; struct node { int x, y, z; } Q[maxn]; struct Node { int x, y, z, id; ll ans; inline void sw() { if (tid[x] > tid[y]) swap(x, y); } inline bool operator < (const Node& b) const { if (tid[x] != tid[b.x]) return tid[x] < tid[b.x]; if (tid[y] != tid[b.y]) return tid[y] < tid[b.y]; return z < b.z; } } query[maxn]; inline void add(int st, int en) { E[num].en = en; E[num].next = head[st]; head[st] = num++; } inline void update(int x) { if (in[x]) ansnow -= (ll)w[cnt[col[x]] --] * v[col[x]]; else ansnow += (ll)w[++cnt[col[x]]] * v[col[x]]; in[x] ^= 1; } inline void modify(int x, int y) { if (in[x]) { update(x); col[x] = y; update(x); } else col[x] = y; } inline void moveto(int x, int y) { while (x != y) { if (dep[x] < dep[y]) swap(x, y); update(x); x = fa[x][0]; } } inline void dfs(int x, int p, int h) { int bt = stn; dep[x] = h; fa[x][0] = p; for (int i = head[x]; i != -1; i = E[i].next) { if (E[i].en == p) continue; dfs(E[i].en, x, h + 1); if (stn - bt >= BLOCKSIZE) { blockclk++; while (stn != bt) tid[st[stn--]] = blockclk; } } st[++stn] = x; } inline void init() { for (int i = 1; i <= 18; i++) for (int j = 1; j <= n; j++) fa[j][i] = fa[fa[j][i - 1]][i - 1]; } inline int LCA(int x, int y) { if (dep[x] < dep[y]) swap(x, y); int t = dep[x] - dep[y]; for (int i = 18; i >= 0; i--) if (t & (1 << i)) x = fa[x][i]; if (x == y) return x; for (int i = 18; i >= 0; i--) { if (fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } } return fa[x][0]; } inline void getans(int x, int y) { update(y); ans[query[x].z] = ansnow; update(y); } int main() { n = read(); m = read(); q = read(); memset(head, -1, sizeof(head)); for (int i = 1; i <= m; i++) v[i] = read(); for (int i = 1; i <= n; i++) w[i] = read(); for (int i = 1; i < n; i++) { int a = read(), b = read(); add(a, b), add(b, a); } BLOCKSIZE = pow(n, 2.0 / 3.0); for (int i = 1; i <= n; i++) col[i] = read(), first[i] = col[i]; dfs(1, 0, 0); while (stn) tid[st[stn--]] = blockclk; init(); int cnt1 = 0, cnt2 = 0; for (int i = 1; i <= q; i++) { int t = read(); if (t == 0) { Q[++cnt1].x = read(); Q[cnt1].y = first[Q[cnt1].x]; Q[cnt1].z = first[Q[cnt1].x] = read(); } else { query[++cnt2].x = read(); query[cnt2].y = read(); query[cnt2].z = cnt2; query[cnt2].id = cnt1; query[cnt2].sw(); } } sort(query + 1, query + cnt2 + 1); int tim = 1; while (tim <= query[1].id) { modify(Q[tim].x, Q[tim].z); tim++; } moveto(query[1].x, query[1].y); getans(1, LCA(query[1].x, query[1].y)); for (int i = 2; i <= cnt2; i++) { while (tim <= query[i].id) modify(Q[tim].x, Q[tim].z), tim++; while (tim > query[i].id + 1) modify(Q[tim - 1].x, Q[tim - 1].y), tim--; moveto(query[i - 1].x, query[i].x); moveto(query[i - 1].y, query[i].y); getans(i, LCA(query[i].x, query[i].y)); } for (int i = 1; i <= cnt2; i++) printf("%lld\n", ans[i]); system("pause"); return 0; }