读题很容易知道这就是一道简单的树上带修改莫队,树上待修改莫队只要将待修改莫队和树上莫队结合起来使用就可以了。(感谢darkbzoj)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<ctime>
#include<algorithm>
#include<sstream>
#include<bitset>
#define scand(a) scanf("%d",&a)
#define scandd(a,b) scanf("%d%d",&a,&b)
#define scanddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mst(a,b) memset(a,b,sizeof(a))
#define lowbit(x) (x&-x)
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fLL;
const int maxn=2e5+5;
const ll mod=1e9+7;
int n,m,blo;
int a[maxn],v[maxn],w[maxn];
struct nod1
{
int l,r,lca,id,pre;
}p[maxn];
struct nod
{
int nxt,to;
}edge[maxn<<1];
struct nod2
{
int pos,val;
}que[maxn];
int head[maxn],cnt=1;
void add(int u,int v)
{
edge[++cnt].nxt=head[u];
edge[cnt].to=v;
head[u]=cnt;
}
int loc[maxn],st[maxn],ed[maxn],ti;
int fa[maxn][21];
int dep[maxn];
void dfs(int u,int f,int depp)
{
loc[++ti]=u;
st[u]=ti;
dep[u]=depp;
fa[u][0]=f;
for(int i=1;i<=20;i++)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==f)continue;
dfs(v,u,depp+1);
}
loc[++ti]=u;
ed[u]=ti;
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)
{
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
}
if(x==y)return x;
for(int i=20;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
}
return fa[x][0];
}
bool cmp(nod1 a,nod1 b)
{
if(a.l/blo==b.l/blo)
{
if(a.r/blo==b.r/blo)return a.pre<b.pre;
return a.r<b.r;
}
return a.l<b.l;
}
ll ans[maxn];
ll k=0;
int vis[maxn];
int sum[maxn];
void upd(int x)
{
if(!vis[x])
{
sum[a[x]]++;
k+=1LL*w[sum[a[x]]]*v[a[x]];
}
else
{
k-=1LL*w[sum[a[x]]]*v[a[x]];
sum[a[x]]--;
}
vis[x]^=1;
}
void cupd(int now,int i)
{
int x=que[now].pos;
if(vis[x])
{
/*
这里的话,由于存在着LCA的缘故,所以直接判断该点有没有访问过就行了,如果访问过,显然这次修改是对答案产生影响的。
*/
upd(x);
swap(a[x],que[now].val);
upd(x);
}
else swap(a[x],que[now].val);//无论有没有影响都得swap,和带修莫队一样
}
int main()
{
#ifdef local
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int n,m,q;
scanddd(n,m,q);
for(int i=1;i<=m;i++)scand(v[i]);
for(int i=1;i<=n;i++)scand(w[i]);
for(int i=1;i<n;i++)
{
int u,v;
scandd(u,v);
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++)scand(a[i]);
dfs(1,0,1);
blo=pow(ti,0.6666);//由于排序是按照带修莫队排的所以最优的块大小肯定是ti^(2/3)
int lenp=0,lenq=0;
for(int i=1;i<=q;i++)//下面按照带修莫队+树上莫队结合着写就行
{
int type,x,y;
scanddd(type,x,y);
if(!type)
{
lenq++;
que[lenq].pos=x;
que[lenq].val=y;
}
else
{
lenp++;
int z=lca(x,y);
if(st[x]>st[y])swap(x,y);
p[lenp].pre=lenq;
p[lenp].id=lenp;
if(z==x)
{
p[lenp].l=st[x];
p[lenp].r=st[y];
}
else
{
p[lenp].lca=z;
p[lenp].l=ed[x];
p[lenp].r=st[y];
}
}
}
sort(p+1,p+1+lenp,cmp);
int l=1,r=0,now=0;
for(int i=1;i<=lenp;i++)
{
while(r>p[i].r)upd(loc[r--]);
while(r<p[i].r)upd(loc[++r]);
while(l<p[i].l)upd(loc[l++]);
while(l>p[i].l)upd(loc[--l]);
while(now<p[i].pre)cupd(++now,i);
while(now>p[i].pre)cupd(now--,i);
if(p[i].lca)upd(p[i].lca);
ans[p[i].id]=k;
if(p[i].lca)upd(p[i].lca);
}
for(int i=1;i<=lenp;i++)printf("%lld\n",ans[i]);
}