寒假里lbn大爷讲离线算法时就讲过了。。。然而现在才明白该怎么做。
这题就是树上带修莫队,带修莫队就是再加一维时间,然后分块size=n^(2/3),时间复杂度O(n^1.67)。树上莫队可以先求出括号序列,若x为y祖先,则两点间的路径为l[x]~l[y],否则就是r[x]~l[y]+lca。没了。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define N 100005
using namespace std;
int n,m,q,p,x,y,sz,v[N],w[N],first[N],c[N],len;
int dep[N],size[N],fa[N],Bson[N],top[N];
int ord[N*2],l[N],r[N],s,vis[N];
int cnt,Ti,la[N],Hz[N],pos[N*2];
ll now,ans[N];
struct edge{int to,next;}e[N*2];
struct Q{int x,y,z,id,lca;}Qry[N];
struct T{int x,u,v;}Mdy[N];
bool cmp(const Q &a,const Q &b)
{return pos[a.x]!=pos[b.x]?pos[a.x]<pos[b.x]:(pos[a.y]!=pos[b.y]?pos[a.y]<pos[b.y]:a.z<b.z);}
void link(int x,int y)
{
e[++len]=(edge){y,first[x]};first[x]=len;
}
void dfs(int x)
{
l[x]=++s;ord[s]=x;
dep[x]=dep[fa[x]]+1;size[x]=1;
for (int i=first[x],t;i;i=e[i].next)
if ((t=e[i].to)!=fa[x])
{
fa[t]=x;dfs(t);size[x]+=size[t];
if (size[t]>size[Bson[x]]) Bson[x]=t;
}
r[x]=++s;ord[s]=x;
}
void dfs(int x,int y)
{
top[x]=y;
if (Bson[x]) dfs(Bson[x],y);
for (int i=first[x],t;i;i=e[i].next)
if ((t=e[i].to)!=fa[x]&&t!=Bson[x])
dfs(t,t);
}
int lca(int x,int y)
{
for (;top[x]!=top[y];x=fa[top[x]])
if (dep[top[x]]<dep[top[y]]) swap(x,y);
return (dep[x]<dep[y])?x:y;
}
void add(int x)
{
if (vis[x]) now-=(ll)v[c[x]]*w[Hz[c[x]]--];
else now+=(ll)v[c[x]]*w[++Hz[c[x]]];
vis[x]^=1;
}
void make(int x,int y)
{
if (vis[x]) add(x),c[x]=y,add(x);else c[x]=y;
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=m;i++)scanf("%d",&v[i]);
for (int i=1;i<=n;i++)scanf("%d",&w[i]);
for (int i=1;i<n;i++)scanf("%d%d",&x,&y),link(x,y),link(y,x);
for (int i=1;i<=n;i++)scanf("%d",&c[i]),la[i]=c[i];
dfs(1);dfs(1,1);sz=(int)pow(s,2.0/3);
for (int i=1;i<=s;i++) pos[i]=(i-1)/sz;
for (int i=1;i<=q;i++)
{
scanf("%d%d%d",&p,&x,&y);
if (p)
{
if (l[x]>l[y]) swap(x,y);
int t=lca(x,y);
if (x!=t) Qry[++cnt]=(Q){r[x],l[y],Ti,cnt,t};
else Qry[++cnt]=(Q){l[x],l[y],Ti,cnt,0};
}
else Mdy[++Ti]=(T){x,la[x],y},la[x]=y;
}
sort(Qry+1,Qry+cnt+1,cmp);
for (int x=1,y=0,z=0,i=1;i<=cnt;i++)
{
while(z<Qry[i].z) z++,make(Mdy[z].x,Mdy[z].v);
while(z>Qry[i].z) make(Mdy[z].x,Mdy[z].u),z--;
while(x>Qry[i].x) add(ord[--x]);
while(y<Qry[i].y) add(ord[++y]);
while(x<Qry[i].x) add(ord[x++]);
while(y>Qry[i].y) add(ord[y--]);
if (Qry[i].lca) add(Qry[i].lca);
ans[Qry[i].id]=now;
if (Qry[i].lca) add(Qry[i].lca);
}
for (int i=1;i<=cnt;i++)
printf("%lld\n",ans[i]);
return 0;
}