[Sdoi2013]森林(启发式合并+主席树)

对于操作1,显然可以使用主席树维护,然后对于一条链(x,y),假设lca为f,根为rt,则(rt,x)+(rt,y)-(rt,f)-(rt,fa[f])即为所求的链,在主席树上直接查询即可,查询方式类似于treap/splay对size的询问。

对于操作2,可以用LCT,当然也能启发式合并,每次连边时,强行把sz小的塞入sz大的即可。

#include<bits/stdc++.h>
using namespace std;
const int N=80100;
int n,m,p,a[N],b[N],rt[N],sz[N],fa[N],dep[N],f[N][20];
vector<int>G[N];
namespace tree{
    struct seg{int lc,rc,s;}tr[N*400];
    int sz;
    void update(int k,int l,int r,int&rt,int prt)
    {
        tr[rt=++sz]=tr[prt],tr[rt].s++;
        if(l==r)return;
        int mid=l+r>>1;
        if(k<=mid)update(k,l,mid,tr[rt].lc,tr[prt].lc);
        else update(k,mid+1,r,tr[rt].rc,tr[prt].rc);
    }
    int query(int u,int v,int pu,int pv,int k,int l,int r)
    {
        if(l==r)return l;
        int mid=l+r>>1,sum=tr[tr[u].lc].s+tr[tr[v].lc].s-tr[tr[pu].lc].s-tr[tr[pv].lc].s;
        if(k<=sum)return query(tr[u].lc,tr[v].lc,tr[pu].lc,tr[pv].lc,k,l,mid);
        return query(tr[u].rc,tr[v].rc,tr[pu].rc,tr[pv].rc,k-sum,mid+1,r);
    }
}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void dfs(int u,int Fa,int anc)
{
    f[u][0]=Fa;
    for(int i=1;i<=19;i++)f[u][i]=f[f[u][i-1]][i-1];
    sz[anc]++,dep[u]=dep[Fa]+1,fa[u]=Fa;
    int x=lower_bound(b+1,b+p+1,a[u])-b;
    tree::update(x,1,p,rt[u],rt[Fa]);
    for(int i=0;i<G[u].size();i++)if(G[u][i]!=Fa)dfs(G[u][i],u,anc);
}
int lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    int t=dep[x]-dep[y];
    for(int i=0;(1<<i)<=t;i++)if(t&(1<<i))x=f[x][i];
    if(x==y)return x;
    for(int i=19;~i;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main()
{
    int Q;scanf("%*d%d%d%d",&n,&m,&Q);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i],fa[i]=i;
    for(int i=1,x,y;i<=m
    ;i++)scanf("%d%d",&x,&y),G[x].push_back(y),G[y].push_back(x);
    sort(b+1,b+n+1);
    p=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)if(!dep[i])dfs(i,0,i),fa[i]=i;
    char op;
    int x,y,z,ans=0;
    while(Q--)
    {
        scanf(" %c%d%d",&op,&x,&y),x^=ans,y^=ans;
        if(op=='Q')
        {
            scanf("%d",&z),z^=ans;
            int Fa=lca(x,y);
            printf("%d
",ans=b[tree::query(rt[x],rt[y],rt[Fa],rt[f[Fa][0]],z,1,p)]);
        }
        else{
            G[x].push_back(y),G[y].push_back(x);
            int fx=find(x),fy=find(y);
            if(sz[fx]<sz[fy])swap(x,y),swap(fx,fy);
            dfs(y,x,fx);
        }
    }
}
View Code
原文地址:https://www.cnblogs.com/hfctf0210/p/10904289.html