树上带修莫队经典题。
有了前面的铺垫:普通带修莫队和普通树上莫队,这题就不在话下了。
答案和走的顺序无关,只和每种糖果吃到几次有关,显然可以O(1)移动维护。
然后就没有然后了……树上带修莫队即可。
这题有点常数问题,在UOJ上被卡了半天90分。最后把块大小调小一些就过了。
好像实际情况下带修莫队块大小不一定是 n2/3 最优,个人感觉稍微调小一点可能效果更好。
#include
#include
#include
using namespace std;
const int maxn=100005, maxe=200005;
typedef long long LL;
int n,m,Q,Q1,Q2,c[maxn],v[maxn],w[maxn],b[maxn],sum[maxn];
LL ans,Ans[maxn];
int son[maxe],fir[maxn],nxt[maxe],tot;
int dfn[maxn],Tim,G,blk,blg[maxn],stk[maxn],top;
bool vis[maxn];
int anc[maxn][20],dep[maxn];
void dfs(int x,int pre){
anc[x][0]=pre; for(int i=1;i<=17;i++) anc[x][i]=anc[anc[x][i-1]][i-1];
dfn[x]=++Tim; int bottom=top;
for(int j=fir[x];j;j=nxt[j]) if(son[j]!=pre){
dep[son[j]]=dep[x]+1; dfs(son[j],x);
if(top-bottom>=blk){
G++;
while(top!=bottom) blg[stk[top--]]=G;
}
}
stk[++top]=x;
}
struct data{ int x,y,id,tim; } q[maxn];
struct OP{ int x,c[2]; } op[maxn];
bool my_cmp(const data &A,const data &B){
if(blg[A.x]==blg[B.x]){
if(blg[A.y]==blg[B.y]) return A.timreturn blg[A.y]y];
}
return blg[A.x]x];
}
inline void add(int x,int y){
son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot;
}
int LCA(int x,int y){
if(dep[x]y]) swap(x,y);
for(int j=17;j>=0;j--) if(dep[anc[x][j]]>=dep[y]) x=anc[x][j];
if(x==y) return x;
for(int j=17;j>=0;j--) if(anc[x][j]!=anc[y][j]) x=anc[x][j], y=anc[y][j];
return anc[x][0];
}
inline int getint(){
char ch=getchar(); int res=0,ff=1;
while(!('0'<=ch&&ch<='9')){ if(ch=='-') ff=-1; ch=getchar(); }
while('0'<=ch&&ch<='9') res=(res<<3)+(res<<1)+ch-'0', ch=getchar();
return res*ff;
}
inline void Updata(int x,int k){
if(k==1) ans+=((LL)w[++sum[x]])*v[x]; else ans-=((LL)w[sum[x]--])*v[x];
}
inline void rev(int x){
if(vis[x]) Updata(c[x],-1); else Updata(c[x],1);
vis[x]^=1;
}
inline void Change(int U,int V,int id,int k){
if(vis[op[id].x]) Updata(c[op[id].x],-1), Updata(op[id].c[k],1);
c[op[id].x]=op[id].c[k];
}
inline void work(int x,int y){
while(x!=y){
if(dep[x]y]) swap(x,y);
rev(x); x=anc[x][0];
}
}
int main(){
freopen("bzoj3052.in","r",stdin);
freopen("bzoj3052.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q);
for(int i=1;i<=m;i++) v[i]=getint();
for(int i=1;i<=n;i++) w[i]=getint();
for(int i=1;i<=n-1;i++){
int x=getint(),y=getint();
add(x,y); add(y,x);
}
for(int i=1;i<=n;i++) c[i]=b[i]=getint();
for(int i=1;i<=Q;i++){
int pd=getint();
if(pd){
Q1++; q[Q1].x=getint(), q[Q1].y=getint(); q[Q1].id=Q1; q[Q1].tim=Q2;
if(dfn[q[Q1].x]>dfn[q[Q1].y]) swap(q[Q1].x,q[Q1].y);
} else{
Q2++; op[Q2].x=getint(); op[Q2].c[1]=getint();
op[Q2].c[0]=b[op[Q2].x]; b[op[Q2].x]=op[Q2].c[1];
}
}
blk=pow(n,0.54); dfs(1,1);
sort(q+1,q+1+Q1,my_cmp);
q[0].x=q[0].y=1; q[0].tim=0;
for(int i=1,now=0;i<=Q1;i++){
while(now<q[i].tim) Change(q[i-1].x,q[i-1].y,++now,1);
while(q[i].timq[i-1].x,q[i-1].y,now--,0);
work(q[i-1].x,q[i].x); work(q[i-1].y,q[i].y);
int _lca=LCA(q[i].x,q[i].y);
rev(_lca); Ans[q[i].id]=ans; rev(_lca);
}
for(int i=1;i<=Q1;i++) printf("%lld\n",Ans[i]);
return 0;
}