题意分析
给定一个树,每次给出两个点 x , y x,y x,y,求这两个点之间的路径上的相关信息,或者修改某个点的值。
算法描述
我们发现,题中所给的操作,可以用带修莫队实现,而把带修莫队放到了树上,这道题就变成了树上带修莫队。
不会树上莫队和带修莫队,可以去看看本人上文中提到的博客无耻的推荐一波自己的博客 ,里面讲的应该比较详细,适合莫队入门。
这道题,我们先用一遍 d f s dfs dfs 将欧拉序求出来,同时预处理出 f f f 数组和 d e p dep dep 数组用于下面的倍增求 L C A LCA LCA。当然求 L C A LCA LCA 的时候也可以用树剖来求,不过求 L C A LCA LCA 不是此题的重点,能求出来即可。对于树上的欧拉序,其实很简单,普通的 d f s dfs dfs 序是每个点第一次被 d f s dfs dfs 到的时候记录下来,那么欧拉序就是每个点进入 d f s dfs dfs 和出 d f s dfs dfs 的时候都记录一下即可。关于欧拉序的性质,本人博客里面也有介绍。简单来说,可以把树上的路径问题,给转化为一段区间,或者是一段区间加上两个点的 L C A LCA LCA。
把树上的欧拉序预处理完之后,考虑进行带修莫队。带修莫队的具体实现,其实就是在普通莫队的基础上多了时间这一维。先把区间的左右端点定好,如果时间戳大了,就往回调,小了就往后调。知道区间和时间同时相等的时候,我们才能说该询问区间与我们得到的区间重合。此时的答案就是该次询问的答案。
至于如何在莫队移动左右指针的时候统计答案,直接用题目中给的式子算贡献即可。注意,由于欧拉序的性质,在一段区间中出现两次的点,不在我们要求的区间内。所以我用一个 v i s vis vis 数组记录下来每个在这个区间的点出现次数。每次操作将 v i s [ i ] vis[i] vis[i] ^ = 1 = 1 =1,表示出没出现过即可。如果没有出现过,那么就要加上这个点的贡献,否则要减去这个点的贡献。最后还是欧拉序的性质,看是否要加上 L C A LCA LCA 这个点对答案的贡献即可。
注意,这道题中给出的 c [ i ] c[i] c[i] 并不是对应树上欧拉序的点的 c [ i ] c[i] c[i],所以我们算 c c c 的时候,里面应该传的是欧拉序的编号。
总代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#define re register
#define int long long
#define drep(a,b,c) for(re int a(b) ; a>=(c) ; --a)
#define rep(a,b,c) for(re int a(b) ; a<=(c) ; ++a)
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
inline void print(int x){
if(x < 0) putchar('-'),x = -x;
if(x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
const int M = 2e5+10;
int head[M],f[M][25],dep[M],v[M],w[M],belong[M],vis[M];
int t[M],cnt[M],c[M],oul[M],st[M],ed[M],typ[M],ans[M];
int n,m,Q,ecnt,oulcnt,qcnt,ccnt,res,B,l=1,r,tim;
struct edge{
int to,nxt;
}e[M];
inline void addedge(int u,int v){
e[++ecnt].to = v;
e[ecnt].nxt = head[u];
head[u] = ecnt;
}
inline void dfs(int u,int fa){
dep[u] = dep[fa] + 1;
f[u][0] = fa;
rep(i,1,20) f[u][i] = f[f[u][i-1]][i-1];
st[u] = ++oulcnt;
oul[oulcnt] = u;
typ[oulcnt] = c[u];
for(re int i(head[u]) ; i ; i=e[i].nxt){
int v = e[i].to;
if(v == fa) continue;
dfs(v,u);
}
ed[u] = ++oulcnt;
oul[oulcnt] = u;
typ[oulcnt] = c[u];
}
inline int getlca(int x,int y){
if(dep[x] < dep[y]) swap(x,y);
drep(i,20,0) if(dep[f[x][i]] >= dep[y]) x = f[x][i];
if(x == y) return x;
drep(i,20,0) if(f[x][i] != f[y][i]) x = f[x][i],y = f[y][i];
return f[x][0];
}
struct node{
int l,r,lca,id,t,bell,belr;
friend bool operator < (node a,node b){
if(a.bell == b.bell){
if(a.belr == b.belr) return a.t < b.t;
if(a.bell&1) return a.r < b.r;
return a.r > b.r;
}
return a.l < b.l;
}
}q[M];
struct qwq{
int pos,val;
}ch[M];
inline void change(int x){
if(vis[ch[x].pos]){
t[c[ch[x].pos]]--;
res -= w[t[c[ch[x].pos]]+1]*v[c[ch[x].pos]];
t[ch[x].val]++;
res += w[t[ch[x].val]]*v[ch[x].val];
}
swap(c[ch[x].pos],ch[x].val);
}
signed main(){
n = read(),m = read(),Q = read();
B = 1145;
rep(i,1,m) v[i] = read();
rep(i,1,n) w[i] = read();
rep(i,1,n-1){
int u = read(),v = read();
addedge(u,v),addedge(v,u);
}
rep(i,1,n) c[i] = read();
dfs(1,0);
rep(i,1,Q){
int op = read(),x = read(),y = read();
if(op == 1){
if(st[x] > st[y]) swap(x,y);
q[++qcnt].lca = getlca(x,y);
q[qcnt].id = qcnt;
q[qcnt].t = ccnt;
if(q[qcnt].lca == x){
q[qcnt].l = st[x];
q[qcnt].r = st[y];
q[qcnt].bell = st[x]/B;
q[qcnt].belr = st[y]/B;
q[qcnt].lca = 0;
}
else{
q[qcnt].l = ed[x];
q[qcnt].r = st[y];
q[qcnt].bell = ed[x]/B;
q[qcnt].belr = st[y]/B;
}
}
else{
ch[++ccnt].pos = x;
ch[ccnt].val = y;
}
}
sort(q+1,q+qcnt+1);
rep(i,1,qcnt){
while(l > q[i].l){
l--;
if(!vis[oul[l]]) t[c[oul[l]]]++,res += w[t[c[oul[l]]]]*v[c[oul[l]]];
else t[c[oul[l]]]--,res -= w[t[c[oul[l]]]+1]*v[c[oul[l]]];
vis[oul[l]] ^= 1;
}
while(r < q[i].r){
r++;
if(!vis[oul[r]]) t[c[oul[r]]]++,res += w[t[c[oul[r]]]]*v[c[oul[r]]];
else t[c[oul[r]]]--,res -= w[t[c[oul[r]]]+1]*v[c[oul[r]]];
vis[oul[r]] ^= 1;
}
while(l < q[i].l){
if(!vis[oul[l]]) t[c[oul[l]]]++,res += w[t[c[oul[l]]]]*v[c[oul[l]]];
else t[c[oul[l]]]--,res -= w[t[c[oul[l]]]+1]*v[c[oul[l]]];
vis[oul[l]] ^= 1;
l++;
}
while(r > q[i].r){
if(!vis[oul[r]]) t[c[oul[r]]]++,res += w[t[c[oul[r]]]]*v[c[oul[r]]];
else t[c[oul[r]]]--,res -= w[t[c[oul[r]]]+1]*v[c[oul[r]]];
vis[oul[r]] ^= 1;
r--;
}
while(tim < q[i].t) change(++tim);
while(tim > q[i].t) change(tim--);
if(q[i].lca){
t[c[q[i].lca]]++;
res += w[t[c[q[i].lca]]]*v[c[q[i].lca]];
}
ans[q[i].id] = res;
if(q[i].lca){
t[c[q[i].lca]]--;
res -= w[t[c[q[i].lca]]+1]*v[c[q[i].lca]];
}
}
rep(i,1,qcnt) printf("%lld\n",ans[i]);
return 0;
}