树上每个点有颜色,每个颜色有一个关于出现次数的权值,定义一条路径的权值为 $sum$ 路径上每个点权值 $ imes$ 它的颜色在路径上出现次数的权值
给 $q$ 次操作,每次修改一个点的颜色或者询问一条路径的权值
$n leq 100000$
sol:
bzoj 200s 极度酸爽
只被我卡了一个人,极度差评
这题如果没有单点修改,是一个树上莫队题,如果有单点修改,就是一个树上带修改莫队题
于是都来写一写:
树上莫队,首先王室联邦分块,维护一下每个点在不在当前路径上
每次暴力爬 $(c_u,q_u),(c_v,q_v)$ 这两条路径修改,最后单算一下 $LCA(q_u,q_v)$ 的贡献即可
带修改莫队,就是在每个询问操作的时候维护一个时间戳,也维护一个当前时间戳,每次把当前时间戳移动到操作时间戳即可
移动时顺便计算/消除每次修改操作的影响,如果有影响,就直接加上去,然后把修改操作改成反向修改操作
这题把这俩东西整到一起就可以了
这份代码很慢,还有可以卡的地方:O(1) lca,使用欧拉序分块,fread,指令集
#include <bits/stdc++.h> #define LL long long #define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i) #define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i) using namespace std; inline int read() { int x = 0, f = 1; char ch; for (ch = getchar(); !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0'; return x * f; } const int maxn = 100010; int n, m, nq, sz, v[maxn], w[maxn], c[maxn]; int first[maxn], to[maxn << 1], nx[maxn << 1], cnt; inline void add(int u, int v) { to[++cnt] = v; nx[cnt] = first[u]; first[u] = cnt; } int size[maxn], fa[maxn], top[maxn], dep[maxn]; inline void sp_dfs1(int x) { size[x] = 1; for(int i=first[x];i;i=nx[i]) { if(to[i] == fa[x]) continue; fa[to[i]] = x; dep[to[i]] = dep[x] + 1; sp_dfs1(to[i]); size[x] += size[to[i]]; } } inline void sp_dfs2(int x, int col) { int k = 0; top[x] = col; for(int i=first[x];i;i=nx[i]) if(to[i] != fa[x] && size[to[i]] > size[k]) k = to[i]; if(!k) return; sp_dfs2(k, col); for(int i=first[x];i;i=nx[i]) if(to[i] != fa[x] && to[i] != k) sp_dfs2(to[i], to[i]); } inline int lca(int x, int y) { while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x, y); x = fa[top[x]]; } return dep[x] < dep[y] ? x : y; } int q[maxn], tp, bl[maxn], bcnt; int fk_dfs(int x) { int cur = 0; for(int i=first[x];i;i=nx[i]) { int v = to[i]; if(v == fa[x]) continue; cur += fk_dfs(v); if(cur >= sz) { bcnt++; while(cur--) bl[q[--tp]] = bcnt; } } q[++tp] = x; return cur + 1; } struct Ques { int u, v, fu, fv, id, t; Ques(){} Ques(int _1, int _2, int _3, int _4, int _5, int _6): u(_1), v(_2), fu(_3), fv(_4), id(_5), t(_6){} bool operator < (const Ques &b) const { if(fu == b.fu) { if(fv == b.fv) return t < b.t; return fv < b.fv; }return fu < b.fu; } }qs[maxn]; struct Chg { int pos, val; Chg(){} Chg(int _1, int _2): pos(_1), val(_2){} }cs[maxn]; int pnt[maxn], vis[maxn]; int qcnt, ccnt, iter; LL ans[maxn], now; inline void opt(int x) { if(vis[x]) { now -= 1LL * v[c[x]] * w[pnt[c[x]]]; pnt[c[x]]--; } else { pnt[c[x]]++; now += 1LL * v[c[x]] * w[pnt[c[x]]]; } vis[x] ^= 1; } inline void move(int &x) { opt(x); x = fa[x]; } inline void change(int tim) { if(vis[cs[tim].pos]) { opt(cs[tim].pos); swap(c[cs[tim].pos], cs[tim].val); opt(cs[tim].pos); } else swap(c[cs[tim].pos], cs[tim].val); } int main() { n = read(), m = read(), nq = read(); sz = (int)pow(n, 0.6666666666666); rep(i, 1, m) v[i] = read(); rep(i, 1, n) w[i] = read(); rep(i, 2, n) { int u = read(), v = read(); add(u, v); add(v, u); }sp_dfs1(1); sp_dfs2(1, 1); fk_dfs(1); rep(i, 1, n) c[i] = read(); rep(i, 1, nq) { int opt = read(), x = read(), y = read(); if(opt == 0) cs[++ccnt] = Chg(x, y); if(opt == 1) { if(bl[x] > bl[y]) swap(x, y); qs[++qcnt] = Ques(x, y, bl[x], bl[y], qcnt, ccnt); } } sort(qs + 1, qs + qcnt + 1); while(tp) bl[q[--tp]] = bcnt; //rep(i, 1, n) cout << bl[i] << " "; //cout << endl; int cu = 1, cv = 1; //return 0; rep(i, 1, qcnt) { //cout << iter << " " << qs[i].t << endl; while(iter < qs[i].t) change(++iter); while(iter > qs[i].t) change(iter--); int qu = qs[i].u, qv = qs[i].v; int anc = lca(cu, qu); while(cu != anc) move(cu); while(qu != anc) move(qu); anc = lca(cv, qv); while(cv != anc) move(cv); while(qv != anc) move(qv); cu = qs[i].u, cv = qs[i].v; anc = lca(cu, cv); opt(anc); ans[qs[i].id] = now; opt(anc); //cout << i << " " << qs[i].id << endl; } rep(i, 1, qcnt) printf("%lld ", ans[i]); } /* 4 3 5 1 9 2 7 6 5 1 2 3 3 1 3 4 1 2 3 2 1 1 2 1 4 2 0 2 1 1 1 2 1 4 2 */