树上莫队
学了发树上莫队。
树上分块是按照王室联邦这道题来分的。
如果没有修改的话直接在树上跳就好了。现在有了修改操作,那么先和带修改莫队一样记一个 ,每次询问前先还原到当前时间。
接下来和序列操作不一样的是移动两个端点。做法是开一个 表示 是否在当前处理的路径上,当从 转移到 时,把 和 路径上的点的 取反并更新答案(不包括 )。
这么做为什么是对的呢?
用 代表 到 的路径上的结点的集合。用 来代表根结点,用 来代表 的最近公共祖先。那么 。其中 是集合的对称差,简单来说就是节点出现两次消掉。
很讨厌,于是再定义
观察将 移动到 前后 变化:
取对称差:
由于对称差的交换律、结合律:
两边同时 :
发现最后两项很爽……哇哈哈
也就是说,更新的时候, 就行了。
即,对 到 路径(除开 )上的结点,将它们的存在性取反即可。
—By vfleaking
代码:
#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define F inline
using namespace std;
typedef long long LL;
struct edge{ int next,to; }ed[N<<1];
struct que{ int x,y,id,t; }q[N];
struct mod{ int x,y,nxt; }a[N];
int n,m,s,k,n1,n2,b,tp,p,nd,h[N],dep[N],fa[N][20];
int ha[N],stk[N],num[N],t[N],v[N],w[N],ti[N],c[N];
LL sum,ans[N]; bool f[N];
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; return *l++;
}
F int _read(){
int x=0,f=1; char ch=readc();
while (!isdigit(ch)) { if (ch=='-') f=-1; ch=readc(); }
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x*f;
}
F void writec(LL x){ if (x>9) writec(x/10); putchar(x%10+48); }
F void _write(LL x){ writec(x),putchar('\n'); }
#define addedge(x,y) ed[++k]=(edge){h[x],y},h[x]=k
F bool cmp(que x,que y){
bool f1=num[x.x]==num[y.x],f2=num[x.y]==num[y.y];
return num[x.x]<num[y.x]||(f1&&num[x.y]<num[y.y])||(f1&&f2&&x.t<y.t);
}
void dfs(int x){
ti[x]=++p; int now=tp;
for (int i=h[x],v;i;i=ed[i].next)
if ((v=ed[i].to)!=fa[x][0]){
fa[v][0]=x,dep[v]=dep[x]+1,dfs(v);
if (tp-now>=b) for (nd++;tp!=now;) num[stk[tp--]]=nd;
}
stk[++tp]=x;
}
F void Make(){
for (int j=1;j<20;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
F int LCA(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int j=19;~j;j--)
if (dep[fa[x][j]]>=dep[y]) x=fa[x][j];
if (x==y) return x;
for (int j=19;~j;j--)
if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
F void rvrs(int x){
if (!f[x]) f[x]=true,t[c[x]]++,sum+=1ll*w[t[c[x]]]*v[c[x]];
else f[x]=false,sum-=1ll*w[t[c[x]]]*v[c[x]],t[c[x]]--;
}
F void mdfy(int x,int y){
if (!f[x]) c[x]=y; else rvrs(x),c[x]=y,rvrs(x);
}
F void srch(int x,int y){
while (x!=y)
if (dep[x]<dep[y]) rvrs(y),y=fa[y][0];
else rvrs(x),x=fa[x][0];
}
int main(){
n=_read(),m=_read(),s=_read();
for (int i=1;i<=m;i++) v[i]=_read();
for (int i=1;i<=n;i++) w[i]=_read();
for (int i=1,x,y;i<n;i++)
x=_read(),y=_read(),addedge(x,y),addedge(y,x);
for (int i=1;i<=n;i++) ha[i]=c[i]=_read();
dep[1]=1,b=(int)pow(n,0.6),dfs(1),Make();
for (int i=1;i<=s;i++){
int f=_read(),x=_read(),y=_read();
if (!f) a[++n2]=(mod){x,y,ha[x]},ha[x]=y;
else{
if (ti[x]>ti[y]) swap(x,y);
q[++n1]=(que){x,y,n1,n2};
}
}
sort(q+1,q+n1+1,cmp);
for (int i=1;i<=q[1].t;i++) mdfy(a[i].x,a[i].y);
srch(q[1].x,q[1].y); int lca=LCA(q[1].x,q[1].y);
rvrs(lca),ans[q[1].id]=sum,rvrs(lca);
for (int i=2,j;i<=n1;i++){
for (j=q[i-1].t+1;j<=q[i].t;j++) mdfy(a[j].x,a[j].y);
for (j=q[i-1].t;j>q[i].t;j--) mdfy(a[j].x,a[j].nxt);
srch(q[i-1].x,q[i].x),srch(q[i-1].y,q[i].y);
int l=LCA(q[i].x,q[i].y);
rvrs(l),ans[q[i].id]=sum,rvrs(l);
}
for (int i=1;i<=n1;i++) _write(ans[i]);
return 0;
}