树上莫队

利用欧拉序序列来确定询问L,R

具体地,当查询u,v。

若lca(u,v)u||lca(u,v)v,[min(in[u],in[v]),max(in[u],in[v])]

否则 [out[u],in[v]] (满足out[u]<in[v])

模板题[https://ac.nowcoder.com/acm/contest/20376/A]

int col[maxn];
vector<int>e[maxn];
struct node{
    int l,r;
    int id;
    int flag;
    int Lca;
};
int idx[maxn];
int cnt=1;
vector<int>V;
int dep[maxn];
int f[maxn];
int anc[maxn][27];
bool cmp(const node&a,const node&b){
    if(idx[a.l]!=idx[b.l])return idx[a.l]<idx[b.l];

    if(idx[a.l]&1){
        return idx[a.r]<idx[b.r];
    }else return idx[a.r]>idx[b.r];
}

void per_dfs(int u,int fa){
    f[u]=fa;
    anc[u][0]=fa;
    dep[u]=dep[fa]+1;
    V.pb(u);
    for(int v:e[u]){
        if(v==fa)continue;
        per_dfs(v,u);
    }
    V.pb(u);
}
int lca(int u,int v){
    if(dep[v]>dep[u])swap(u,v);
    for(int j=26;j>=0;j--){
        if(dep[anc[u][j]]>=dep[v]){
            u=anc[u][j];
        }
        if(u==v)return u;
    }

    for(int j=26;j>=0;j--){
        if(anc[u][j]!=anc[v][j]){
            u=anc[u][j];
            v=anc[v][j];
        }
    }
    return anc[u][0];
}

int vis[maxn];
int tot[maxn];
int ans[maxn];
int in[maxn];
int out[maxn];
node qr[maxn];
int sum=0;
void modify(int p){
    if(vis[p]){
        tot[col[p]]--;
        if(tot[col[p]]==0)sum--;
    }else{
        tot[col[p]]++;
        if(tot[col[p]]==1)sum++;
    }
    vis[p]^=1;
}
void solve(){
    int n;cin>>n;
    rep(i,1,n)cin>>col[i];
    dep[0]=-1;
    V.pb(0);

    int bs= (int)pow(2*n,2.0/3.0);
    rep(i,1,2*n){
        if(i>cnt*bs)cnt++;idx[i]=cnt;
    }
    rep(i,1,n-1){
        int u,v;cin>>u>>v;
        e[u].pb(v);e[v].pb(u);
    }
    per_dfs(1,0);
    for(int j=1;j<=26;j++){
        for(int i=1;i<=n;i++){
            anc[i][j]=anc[anc[i][j-1]][j-1];
        }
    }
    for(int i=1;i<=2*n;i++){
        if(!in[V[i]])in[V[i]]=i;
        else out[V[i]]=i;
    }

    int q;cin>>q;
    rep(i,1,q){
        int u,v;cin>>u>>v;
        int L=0,R=0,flag=0;
        if(lca(u,v)==u||lca(u,v)==v){
            L=min(in[u],in[v]);
            R=max(in[u],in[v]);
        }else{
            if(out[u]<in[v]){
                L=out[u];R=in[v];
            }else L=out[v],R=in[u];
            flag=1;
        }
        qr[i].id=i;qr[i].l=L;qr[i].r=R;qr[i].flag=flag;qr[i].Lca=lca(u,v);
    }
    
    sort(qr+1,qr+1+q,cmp);

    int L=1,R=0;
    rep(i,1,q){
        int _l=qr[i].l,_r=qr[i].r;
        while(L<_l)modify(V[L++]);
        while(L>_l)modify(V[--L]);
        while(R<_r)modify(V[++R]);
        while(R>_r)modify(V[R--]);
        if(qr[i].flag){
            modify(qr[i].Lca);
            ans[qr[i].id]=sum;
            modify(qr[i].Lca);
        }else ans[qr[i].id]=sum;
    }

    for(int i=1;i<=q;i++)cout<<ans[i]<<endl;
}
posted @ 2025-08-14 21:51  Marinaco  阅读(6)  评论(0)    收藏  举报
//雪花飘落效果