题解:
启发式合并主席树
时间复杂度O(nlogn*logn)
空间复杂度O(nlogn*logn)
Woc初始的时候也用了启发式合并建图,然后RE成翔了
一开始算错了空间,下次注意
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> using namespace std; const int maxn=100000; int n,m,TT; int a[maxn]; int lastans=0; int cntedge=0; int head[maxn]={0}; int to[maxn<<1]={0},nex[maxn<<1]={0}; void Addedge(int x,int y){ nex[++cntedge]=head[x]; to[cntedge]=y; head[x]=cntedge; } int b[maxn],nn; struct PresidentTree{ int ls,rs,d; }tree[maxn*100]; int Tsize=0; int root[maxn]={0}; void BuildTree(int &now,int l,int r){ now=++Tsize; tree[now].d=0; if(l==r)return; int mid=(l+r)>>1; BuildTree(tree[now].ls,l,mid); BuildTree(tree[now].rs,mid+1,r); } void Updatapoint(int &now,int l,int r,int pre,int p){ now=++Tsize; tree[now]=tree[pre]; tree[now].d++; if(l==r)return; int mid=(l+r)>>1; if(p<=mid)Updatapoint(tree[now].ls,l,mid,tree[pre].ls,p); else Updatapoint(tree[now].rs,mid+1,r,tree[pre].rs,p); } int Queryans(int l,int r,int x,int y,int z,int t,int k){ if(l==r)return b[l]; int lx=tree[x].ls,ly=tree[y].ls,lz=tree[z].ls,lt=tree[t].ls; int d=tree[lx].d+tree[ly].d-tree[lz].d-tree[lt].d; int mid=(l+r)>>1; if(k<=d)return Queryans(l,mid,lx,ly,lz,lt,k); else return Queryans(mid+1,r,tree[x].rs,tree[y].rs,tree[z].rs,tree[t].rs,k-d); } int f[maxn][20]; int dep[maxn]; void Dfs(int x,int fa){ dep[x]=dep[fa]+1; f[x][0]=fa; for(int j=1;j<=19;++j){ f[x][j]=f[f[x][j-1]][j-1]; } Updatapoint(root[x],1,nn,root[fa],a[x]); for(int i=head[x];i;i=nex[i]){ if(to[i]==fa)continue; Dfs(to[i],x); } } int Getlca(int u,int v){ if(dep[u]<dep[v])swap(u,v); for(int j=19;j>=0;--j){ if(dep[f[u][j]]>=dep[v]){ u=f[u][j]; } } if(u==v)return u; for(int j=19;j>=0;--j){ if(f[u][j]!=f[v][j]){ u=f[u][j];v=f[v][j]; } } return f[u][0]; } int Getans(int u,int v,int k){ int lca=Getlca(u,v); return Queryans(1,nn,root[u],root[v],root[lca],root[f[lca][0]],k); } int father[maxn]; int siz[maxn]; int Getf(int x){ if(father[x]==x)return x; return father[x]=Getf(father[x]); } void Unionn(int x,int y){ int fx=Getf(x); int fy=Getf(y); siz[fy]+=siz[fx]; father[fx]=fy; } int testcase; int main(){ scanf("%d",&testcase); scanf("%d%d%d",&n,&m,&TT); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+1+n); nn=unique(b+1,b+1+n)-b-1; for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+1+nn,a[i])-b; BuildTree(root[0],1,nn); for(int i=1;i<=n;++i){ father[i]=i;siz[i]=1; } while(m--){ int x,y; scanf("%d%d",&x,&y); Addedge(x,y); Addedge(y,x); Unionn(x,y); } for(int i=1;i<=n;++i){ if(!root[i])Dfs(i,0); } while(TT--){ char opty=getchar(); while(opty!=‘Q‘&&opty!=‘L‘)opty=getchar(); int x,y,z; scanf("%d%d",&x,&y); x^=lastans;y^=lastans; if(opty==‘Q‘){ scanf("%d",&z); z^=lastans; printf("%d\n",lastans=Getans(x,y,z)); }else{ int fx=Getf(x); int fy=Getf(y); Addedge(x,y); Addedge(y,x); if(Getf(x)==Getf(y))exit(0); if(siz[fx]<siz[fy]){ Dfs(x,y); }else{ Dfs(y,x); } Unionn(x,y); } } return 0; }