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;
}

不愧是莫队集大成者

01-06 18:32