题目来源:BZOJ 3052 UOJ 58
思路:
把树转化为欧拉序,把询问映射到欧拉序上,在欧拉序上跑带修改莫队。
具体的做法可以参考<国家集训队2014论文集.pdf>的第82页描述的性质。
<国家集训队2014论文集.pdf> 6.3M 百度云链接 密码: p4n2
代码:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 200010;
int n, m, qq, uu, vv, qcnt, tmp, ccnt, dcnt, blsz, l, r, tm;
int c[maxn], bl[maxn];
int ne[maxn], po[maxn], fa[maxn], dep[maxn], sz[maxn], dfn[maxn*2];
int son[maxn], top[maxn], in[maxn], out[maxn], vnum[maxn];
long long ans[maxn], res, v[maxn], w[maxn];
vector <int> head[maxn];
bool is[maxn];
struct node{int l, r, id, lca, time;}q[maxn];
inline bool cmp(const node a, const node b){
if(bl[a.l] == bl[b.l]){
if(bl[a.r] == bl[b.r]) return a.time < b.time;
else return bl[a.r] < bl[b.r];
}else return bl[a.l] < bl[b.l];
}
inline int gt(){
char c = ' '; int num = 0, ok = 0;
while(1){
c = getchar();
if(c <= '9' && c >= '0') num = num*10+c-'0', ok = 1;
else if(ok) return num;
}
}
void dfs1(int x){
dfn[in[x] = ++dcnt] = x, sz[x] = 1; int SZ = 0, SZnum = 0;
for(int i = 0; i < head[x].size(); i ++){
int u = head[x][i]; if(u == fa[x]) continue;
fa[u] = x, dep[u] = dep[x] + 1;
dfs1(u); sz[x] += sz[u];
if(sz[u] > SZ) SZ = sz[u], SZnum = u;
} son[x] = SZnum;
dfn[out[x] = ++dcnt] = x;
}
void dfs2(int x, int tp){
top[x] = tp;
if(son[x] != 0) dfs2(son[x], tp);
for(int i = 0; i < head[x].size(); i ++){
int u = head[x][i];
if(u == fa[x] || u == son[x]) continue;
dfs2(u, u);
}
}
int lca(int u, int v){
while(top[u] != top[v])
dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
return dep[u] < dep[v] ? u : v;
}
void add(int x){
vnum[c[x]] ++;
res += w[vnum[c[x]]] * v[c[x]];
}
void del(int x){
res -= w[vnum[c[x]]] * v[c[x]];
vnum[c[x]] --;
}
void Xor(int x){
if(is[x]) del(x);
else add(x);
is[x] ^= 1;
}
int main(){
n = gt(), m = gt(), qq = gt();
for(int i = 1; i <= m; i ++) v[i] = gt();
for(int i = 1; i <= n; i ++) w[i] = gt();
for(int i = 1; i < n; i ++){
uu = gt(), vv = gt();
head[uu].push_back(vv);
head[vv].push_back(uu);
} dfs1(1), dfs2(1, 1);
blsz = max(1.0, pow(dcnt, 2.0/3));
for(int i = 1; i <= dcnt; i ++) bl[i] = (i-1)/blsz + 1;
for(int i = 1; i <= n; i ++) c[i] = gt();
for(int i = 1; i <= qq; i ++){
tmp = gt();
if(tmp){
q[++qcnt].l = gt(), q[qcnt].r = gt();
q[qcnt].lca = lca(q[qcnt].l, q[qcnt].r);
if(in[q[qcnt].l] > in[q[qcnt].r]) swap(q[qcnt].l, q[qcnt].r);
if(q[qcnt].lca == q[qcnt].l){
q[qcnt].l = in[q[qcnt].l], q[qcnt].r = in[q[qcnt].r];
q[qcnt].lca = 0;
}else{
if(out[q[qcnt].l] > in[q[qcnt].r]) swap(q[qcnt].l, q[qcnt].r);
q[qcnt].l = out[q[qcnt].l], q[qcnt].r = in[q[qcnt].r];
}
q[qcnt].id = qcnt, q[qcnt].time = ccnt;
}else po[++ccnt] = gt(), ne[ccnt] = gt();
}
sort(q+1, q+1+qcnt, cmp);
l = 1, r = 0, tm = 0;
for(int i = 1; i <= qcnt; i ++){
for( ; tm < q[i].time; tm ++){
if((in[po[tm+1]] <= r && in[po[tm+1]] >= l)^
(out[po[tm+1]] <= r && out[po[tm+1]] >= l)){
res -= w[vnum[c[po[tm+1]]]]*v[c[po[tm+1]]];
vnum[c[po[tm+1]]] --;
}
swap(c[po[tm+1]], ne[tm+1]);
if((in[po[tm+1]] <= r && in[po[tm+1]] >= l)^
(out[po[tm+1]] <= r && out[po[tm+1]] >= l)){
vnum[c[po[tm+1]]] ++;
res += w[vnum[c[po[tm+1]]]]*v[c[po[tm+1]]];
}
}
for( ; tm > q[i].time; tm --){
if((in[po[tm]] <= r && in[po[tm]] >= l)^
(out[po[tm]] <= r && out[po[tm]] >= l)){
res -= w[vnum[c[po[tm]]]]*v[c[po[tm]]];
vnum[c[po[tm]]] --;
}
swap(c[po[tm]], ne[tm]);
if((in[po[tm]] <= r && in[po[tm]] >= l)^
(out[po[tm]] <= r && out[po[tm]] >= l)){
vnum[c[po[tm]]] ++;
res += w[vnum[c[po[tm]]]]*v[c[po[tm]]];
}
}
for( ; l > q[i].l; l --) Xor(dfn[l-1]);
for( ; r < q[i].r; r ++) Xor(dfn[r+1]);
for( ; l < q[i].l; l ++) Xor(dfn[l]);
for( ; r > q[i].r; r --) Xor(dfn[r]);
if(q[i].lca != 0){
add(q[i].lca);
ans[q[i].id] = res;
del(q[i].lca);
}else ans[q[i].id] = res;
}
for(int i = 1; i <= qcnt; i ++) printf("%lld\n", ans[i]);
return 0;
}