P4074 [WC2013]糖果公园
因为一些原因,这篇博客一直咕着,现在终于有机会重拾旧话
解法:dfs序+带修莫队+lca
dfs序保证询问连续,带修莫队处理数颜色
lca的作用是:去除lca对答案的影响
代码:
#include<bits/stdc++.h> using namespace std; const int N=500005; typedef long long ll; struct TIM{ int pos;//DFS序列上的修改位置 int last; int now; }t[N]; struct node{ int time; int l,r; int rank; int LB,RB; bool flag; }S[N]; int n,m,q; int F[N][22]; ll value[N]; ll kind[N]; int C[N]; int CCC[N]; int hed[N],tal[N],nxt[N]; int f[N],cnt=0; int IN[N],OUT[N]; int DFSX[N]; int CNT=0; int be[N]; int len,block; ll kans[N]={0}; ll ans=0; int l=1,r=0,tim=1; int chose[N]={0};//某个位置是否用过 ll happen[N]={0};//某种糖果出现次数 int UID=0; int dep[N]; int col[N]={0}; void addege(int x,int y){ cnt++; tal[cnt]=y; nxt[cnt]=hed[x]; hed[x]=cnt; } void dfs(int u,int fa){ DFSX[++CNT]=u; IN[u]=CNT; for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fa) continue; f[v]=u; dep[v]=dep[u]+1; dfs(v,u); } DFSX[++CNT]=u; OUT[u]=CNT; } bool cmp(node x,node y){ if(be[x.l]==be[y.l]){ if(be[x.r]==be[y.r]){ return x.time<y.time; } else return x.r<y.r; } else return x.l<y.l; } int lca(int x,int y){ if(dep[x]>dep[y]) swap(x,y); for(register int i=20;i>=0;i--){ if(dep[x]<=dep[F[y][i]]) y=F[y][i]; } if(x==y) return x; for(register int i=20;i>=0;i--){ if(F[x][i]!=F[y][i]){ x=F[x][i]; y=F[y][i]; } } return f[x]; } void add(int pos){ if(chose[pos]) ans-=1ll*value[col[pos]]*kind[happen[col[pos]]--]; else ans+=1ll*value[col[pos]]*kind[++happen[col[pos]]]; chose[pos]^=1; } void ch(int x,int c){ if(chose[x]){ add(x); col[x]=c; add(x); } else col[x]=c; } int main(){ scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=m;i++) scanf("%lld",&value[i]); for(int i=1;i<=n;i++) scanf("%lld",&kind[i]); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); addege(x,y); addege(y,x); } dep[1]=1; dfs(1,-1); f[1]=1; for(int i=0;i<=18;i++){ for(int j=1;j<=n;j++){ if(i==0) F[j][i]=f[j]; else F[j][i]=F[F[j][i-1]][i-1]; } } //for(int i=1;i<=CNT;i++) cout<<DFSX[i]<<endl; for(int i=1;i<=n;i++) scanf("%d",&C[i]),CCC[i]=C[i]; len=pow(n,0.6); for(int i=1;i<=2*n;i++){ be[i]=(i/len)+1; } int cntA=0,cntB=0; for(int i=1;i<=q;i++){ int A,B,C; scanf("%d%d%d",&A,&B,&C); if(A==0){ cntA++; t[cntA].pos=B; t[cntA].last=CCC[B]; t[cntA].now=C; CCC[B]=C; } else{ if(IN[B]>IN[C]) swap(B,C); S[++cntB].rank=cntB; S[cntB].l=(lca(B,C)==B?IN[B]:OUT[B]); S[cntB].r=IN[C]; S[cntB].time=cntA; } } for(int i=1;i<=n;i++) col[i]=C[i]; sort(S+1,S+cntB+1,cmp); //cout<<IN[2]<<" "<<IN[3]<<" "<<IN[1]<<endl; for(int i=1;i<=cntB;i++){ while(tim<=S[i].time){ ch(t[tim].pos,t[tim].now); tim++; } while(tim>S[i].time){ ch(t[tim].pos,t[tim].last); tim--; } while(l<S[i].l){ add(DFSX[l]); l++; } while(l>S[i].l){ l--; add(DFSX[l]); } while(r<S[i].r){ r++; add(DFSX[r]); } while(r>S[i].r){ add(DFSX[r]); r--; } int x=DFSX[l],y=DFSX[r],z=lca(x,y); if(x!=z&&y!=z) add(z),kans[S[i].rank]=ans,add(z); else kans[S[i].rank]=ans; } for(int i=1;i<=cntB;i++){ printf("%lld\n",kans[i]); } return 0; }
不愧是莫队集大成者