树上莫队
学了发树上莫队。
树上分块是按照王室联邦这道题来分的。
如果没有修改的话直接在树上跳就好了。现在有了修改操作,那么先和带修改莫队一样记一个 t t ,每次询问前先还原到当前时间。
接下来和序列操作不一样的是移动两个端点。做法是开一个表示 i i 是否在当前处理的路径上,当从转移到 (x2,y2) ( x 2 , y 2 ) 时,把 (x1,x2) ( x 1 , x 2 ) 和 (y1,y2) ( y 1 , y 2 ) 路径上的点的 f f 取反并更新答案(不包括)。
这么做为什么是对的呢?
用 S(v,u) S ( v , u ) 代表 v v 到的路径上的结点的集合。用 root r o o t 来代表根结点,用 lca(v,u) l c a ( v , u ) 来代表 v,u v , u 的最近公共祖先。那么 S(v,u)=S(root,v) xor S(root,u) xor lca(v,u) S ( v , u ) = S ( r o o t , v ) x o r S ( r o o t , u ) x o r l c a ( v , u ) 。其中 xor x o r 是集合的对称差,简单来说就是节点出现两次消掉。
lca l c a 很讨厌,于是再定义 T(v,u)=S(root,v) xor S(root,u) T ( v , u ) = S ( r o o t , v ) x o r S ( r o o t , u )
观察将 curV c u r V 移动到 targetV t a r g e t V 前后 T(curV,curU) T ( c u r V , c u r U ) 变化:
T(curV,curU)=S(root,curV) xor S(root,curU) T ( c u r V , c u r U ) = S ( r o o t , c u r V ) x o r S ( r o o t , c u r U )
T(targetV,curU)=S(root,targetV) xor S(root,curU) T ( t a r g e t V , c u r U ) = S ( r o o t , t a r g e t V ) x o r S ( r o o t , c u r U )
取对称差:
T(curV,curU) xor T(targetV,curU)=(S(root,curV) xor S(root,curU)) xor (S(root,targetV) xor S(root,curU)) T ( c u r V , c u r U ) x o r T ( t a r g e t V , c u r U ) = ( S ( r o o t , c u r V ) x o r S ( r o o t , c u r U ) ) x o r ( S ( r o o t , t a r g e t V ) x o r S ( r o o t , c u r U ) )
由于对称差的交换律、结合律:
T(curV,curU) xor T(targetV,curU)=S(root,curV) xor S(root,targetV) T ( c u r V , c u r U ) x o r T ( t a r g e t V , c u r U ) = S ( r o o t , c u r V ) x o r S ( r o o t , t a r g e t V )
两边同时 xor T(curV,curU) x o r T ( c u r V , c u r U ) :
T(targetV,curU)=T(curV,curU) xor S(root,curV) xor S(root,targetV) T ( t a r g e t V , c u r U ) = T ( c u r V , c u r U ) x o r S ( r o o t , c u r V ) x o r S ( r o o t , t a r g e t V )
发现最后两项很爽……哇哈哈
T(targetV,curU)=T(curV,curU) xor T(curV,targetV) T ( t a r g e t V , c u r U ) = T ( c u r V , c u r U ) x o r T ( c u r V , t a r g e t V )
也就是说,更新的时候, xor T(curV,targetV) x o r T ( c u r V , t a r g e t V ) 就行了。
即,对 curV c u r V 到 targetV t a r g e t V 路径(除开 lca(curV,targetV) l c a ( c u r V , t a r g e t V ) )上的结点,将它们的存在性取反即可。
—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;
}