AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3052
【题解】
这题是带修改的树上莫队,坑爹的200s
用S(x,y)表示x到y路径上的点集,然后定义一种xor运算:S(x1,y1)xorS(x2,y2)表示把点集内重复的点删掉的并集。
设t是x、y的lca
那么显然S(x,y)=S(root,x) xor S(root,y) xor t
然后定义T(x,y)=S(root,x) xor S(root,y)
那么从x移动到dx,T(dx,y)=S(root,dx) xor S(root,y)
T(dx,y) xor T(x,y)=S(root,dx) xor S(root,x)=T(dx,x)
T(dx,y)=T(x,y) xor T(dx,x)
也就是说更新答案时只需要xor(dx,x)即可(对于y结点也一样的)
对于树分块,我们把块的大小设为n^(2/3),这样时间复杂度为O(n ^ (5 / 3))
/*************
bzoj 3052
by chty
2016.11.26
*************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define FILE "read"
#define MAXN 100010
#define up(i,j,n) for(int i=j;i<=n;i++)
#define down(i,j,n) for(int i=j;i>=n;i--)
typedef long long ll;
struct node{int y,next;}e[MAXN*2];
struct NODE{int x,y,id,pre,time;}b[MAXN],c[MAXN];
int n,m,q,len,block,cnt1,cnt2,top,bcnt,dfs_clock;
ll now,ans[MAXN],V[MAXN],W[MAXN],C[MAXN],pre[MAXN];
int Link[MAXN],stack[MAXN],belong[MAXN],vis[MAXN],num[MAXN],deep[MAXN],dfn[MAXN],bin[23],anc[MAXN][23];
namespace INIT{
char buf[1<<15],*fs,*ft;
inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline int read(){
int x=0,f=1; char ch=getc();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getc();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getc();}
return x*f;
}
}using namespace INIT;
bool operator <(NODE a,NODE b){
if(belong[a.x]==belong[b.x]&&belong[a.y]==belong[b.y]) return a.time<b.time;
else if(belong[a.x]==belong[b.x]) return belong[a.y]<belong[b.y];
else return belong[a.x]<belong[b.x];
}
void insert(int x,int y) {e[++len].next=Link[x];Link[x]=len;e[len].y=y;}
int dfs(int x){
int size=0; dfn[x]=++dfs_clock;
up(i,1,16) if(deep[x]>=bin[i])anc[x][i]=anc[anc[x][i-1]][i-1];else break;
for(int i=Link[x];i;i=e[i].next)
if(anc[x][0]!=e[i].y){
anc[e[i].y][0]=x;
deep[e[i].y]=deep[x]+1;
size+=dfs(e[i].y);
if(size>=block){
bcnt++;
up(j,1,size) belong[stack[top--]]=bcnt;
size=0;
}
}
stack[++top]=x;
return size+1;
}
int lca(int x,int y){
if(deep[x]<deep[y])swap(x,y);
int t=deep[x]-deep[y];
for(int i=0;bin[i]<=t;i++)
if(bin[i]&t)
x=anc[x][i];
for(int i=16;i>=0;i--)
if(anc[x][i]!=anc[y][i])
x=anc[x][i],y=anc[y][i];
if(x==y)return x;
return anc[x][0];
}
void cal(int x){
if(vis[x]) now-=V[C[x]]*W[num[C[x]]--];
else now+=V[C[x]]*W[++num[C[x]]];
vis[x]^=1;
}
void change(int x,int y){
if(vis[x]) {cal(x); C[x]=y; cal(x);}
else C[x]=y;
}
void solve(int x,int y){
while(x!=y){
if(deep[x]>deep[y]) cal(x),x=anc[x][0];
else cal(y),y=anc[y][0];
}
}
void init(){
n=read(); m=read(); q=read(); block=pow(n,2.0/3)*0.5;
up(i,1,m) V[i]=read();
up(i,1,n) W[i]=read();
bin[0]=1; up(i,1,20) bin[i]=bin[i-1]<<1;
up(i,1,n-1) {int x=read(),y=read(); insert(x,y); insert(y,x);}
up(i,1,n) pre[i]=C[i]=read();
dfs(1);
while(top) belong[stack[top--]]=bcnt;
up(i,1,q){
int flag=read(),x=read(),y=read();
if(!flag) {c[++cnt2].x=x; c[cnt2].y=y; c[cnt2].pre=pre[x]; pre[x]=y;}
else {if(dfn[x]>dfn[y])swap(x,y);b[++cnt1].x=x; b[cnt1].y=y; b[cnt1].id=cnt1; b[cnt1].time=cnt2;}
}
}
void solve(){
sort(b+1,b+cnt1+1);
up(i,1,b[1].time) change(c[i].x,c[i].y);
solve(b[1].x,b[1].y); int t=lca(b[1].x,b[1].y);
cal(t); ans[b[1].id]=now; cal(t);
up(i,2,cnt1){
up(j,b[i-1].time+1,b[i].time) change(c[j].x,c[j].y);
down(j,b[i-1].time,b[i].time+1) change(c[j].x,c[j].pre);
solve(b[i-1].x,b[i].x);
solve(b[i-1].y,b[i].y);
int t=lca(b[i].x,b[i].y);
cal(t); ans[b[i].id]=now; cal(t);
}
up(i,1,cnt1) printf("%lld\n",ans[i]);
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
init();
solve();
return 0;
}