主席树+启发式合并
(我以前的主席树板子是错的.......坑了我老久TAT)
第k小问题显然是主席树。
我们对每个点维护一棵包含其子树所有节点的主席树
询问(x,y)的时候用倍增找到(x,y)的lca,蓝后树上差分一下,即:
$total_{size}=sum[x]+sum[y]-sum[lca]-sum[fa[lca]]$
至于合并两棵树........我们把小的那棵树接到大的那棵上,并把小树上的主席树都重构一遍
这就是启发式合并,合并的复杂度大概为$O(nlogn)$
数据......离散化一下就好辣
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline void Swap(int &a,int &b){a^=b^=a^=b;} void read(int &x){ static char c=getchar();x=0; int f=1; while(c<'0'||c>'9') f=f&&(c!='-'),c=getchar(); while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar(); x=f?x:-x; } #define N 80005 #define W 20000005 int TAT,n,m,T,tn,a[N],b[N],w[N],Rt[N],Siz[N],Pre; int u,rt[N],lc[W],rc[W],siz[W]; int fa[N],Fa[18][N],d[N]; int cnt,hd[N],nxt[N<<1],ed[N],poi[N<<1]; bool vis[N]; inline void adde(int x,int y){ nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt, ed[x]=cnt, poi[cnt]=y; } inline int Id(int x){return lower_bound(b+1,b+tn+1,x)-b;} #define mid (l+r)/2 void Ins(int &o,int p,int l,int r,int x){ if(!o) o=++u; siz[o]=siz[p]+1; if(l==r) return ; if(x<=mid) rc[o]=rc[p],Ins(lc[o],lc[p],l,mid,x); else lc[o]=lc[p],Ins(rc[o],rc[p],mid+1,r,x); } int Ask(int x,int y,int c1,int c2,int l,int r,int k){ if(l==r) return b[l]; int tmp=siz[lc[x]]+siz[lc[y]]-siz[lc[c1]]-siz[lc[c2]]; if(k<=tmp) return Ask(lc[x],lc[y],lc[c1],lc[c2],l,mid,k); else return Ask(rc[x],rc[y],rc[c1],rc[c2],mid+1,r,k-tmp); } void dfs(int x,int RT){ Fa[0][x]=fa[x]; d[x]=d[fa[x]]+1; vis[x]=1; for(int i=1;i<=17;++i) Fa[i][x]=Fa[i-1][Fa[i-1][x]];//不能写成(1<<i)<=d[x],因为我们并没有把之前的废弃点完全删除,必须全部覆盖掉 ++Siz[RT]; Rt[x]=RT; Ins(rt[x],rt[fa[x]],1,tn,Id(a[x])); for(int i=hd[x];i;i=nxt[i]) if(poi[i]!=fa[x]) fa[poi[i]]=x,dfs(poi[i],RT); } int LCA(int x,int y){ if(d[x]<d[y]) Swap(x,y); for(int i=17;i>=0;--i) if(d[Fa[i][x]]>=d[y]) x=Fa[i][x]; if(x==y) return x; for(int i=17;i>=0;--i) if(Fa[i][x]!=Fa[i][y]) x=Fa[i][x],y=Fa[i][y]; return Fa[0][x]; } int main(){ register int i; char opt[3]; int q1,q2,q3,lca; read(TAT);read(n);read(m);read(T); for(i=1;i<=n;++i) read(a[i]),w[i]=a[i]; while(m--) read(q1),read(q2),adde(q1,q2),adde(q2,q1); sort(w+1,w+n+1); b[tn=1]=w[1]; for(i=2;i<=n;++i) if(w[i]!=w[i-1]) b[++tn]=w[i]; //离散化 for(i=1;i<=n;++i) if(!vis[i]) dfs(i,i); while(T--){ scanf("%s",opt);read(q1);read(q2);q1^=Pre;q2^=Pre; if(opt[0]=='L'){ adde(q1,q2),adde(q2,q1); if(Siz[Rt[q1]]<Siz[Rt[q2]]) Swap(q1,q2); fa[q2]=q1; dfs(q2,Rt[q1]);//启发式合并,小树连到大树上 }else{ read(q3); q3^=Pre; lca=LCA(q1,q2); Pre=Ask(rt[q1],rt[q2],rt[lca],rt[fa[lca]],1,tn,q3); printf("%d ",Pre); } }return 0; }