题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3123
主席树+启发式合并。
首先对于每棵树建主席树,然后合并的时候就把点数小的暴力插进点数大的那棵树里面。
然后查询的话就在主席树上二分就可以了。
注意点:在暴力重建的过程中边是确确实实要连的否则会丢失信息。。
调了很久TAT。。
#include<cstring> #include<iostream> #include<algorithm> #include<cstdio> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define inf 1000000009 #define ll long long using namespace std; struct data{int obj,pre; }e[165000]; int sum[24005000],root[80050],ls[24005000],rs[24005000]; int head[80050],dep[80050],fa[80050][21],a[80050],b[80050],s[80050]; int bin[21]; int n,m,q,ans,tot,cnt,tt,num; char ch[2]; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();} return x*f; } void insert(int x,int y){ e[++tot].obj=y; e[tot].pre=head[x]; head[x]=tot; } void add(int l,int r,int x,int &y,int val){ y=++cnt; sum[y]=sum[x]+1; if (l==r) return; int mid=(l+r)/2; if (val<=mid) rs[y]=rs[x],add(l,mid,ls[x],ls[y],val); if (val>mid) ls[y]=ls[x],add(mid+1,r,rs[x],rs[y],val); } void dfs(int u){ s[u]=1; add(1,num,root[fa[u][0]],root[u],a[u]); rep(i,1,20) if (dep[u]>=bin[i]) fa[u][i]=fa[fa[u][i-1]][i-1]; for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (v!=fa[u][0]){ fa[v][0]=u; dep[v]=dep[u]+1; dfs(v); s[u]+=s[v]; } } } int lca(int x,int y){ if (dep[x]<dep[y]) swap(x,y); int t=dep[x]-dep[y]; rep(i,0,20) if (t&bin[i]) x=fa[x][i]; down(i,20,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; if (x==y) return x; return fa[x][0]; } void cl(int u,int f){ clr(fa[u],0); dep[u]=0; for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (v!=f) cl(v,u); } } void link(int x,int y){ cl(y,0); dep[y]=dep[x]+1; fa[y][0]=x; insert(x,y); insert(y,x); dfs(y); } void rebuild(int x,int y){ int sx=x,sy=y; int t=dep[x]; rep(i,0,20) if (t&bin[i]) x=fa[x][i]; t=dep[y]; rep(i,0,20) if (t&bin[i]) y=fa[y][i]; if (s[x]<s[y]) swap(x,y),swap(sx,sy); s[x]+=s[y]; link(sx,sy); } int solve(int x,int y,int k){ int z=lca(x,y),t=fa[z][0],a=root[x],b=root[y],c=root[z],d=root[t]; int l=1,r=num,now=0; while (l<r){ int mid=(l+r)/2; now=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]]; if (now<k) { k-=now; a=rs[a],b=rs[b],c=rs[c],d=rs[d]; l=mid+1; } else { a=ls[a],b=ls[b],c=ls[c],d=ls[d]; r=mid; } } return l; } int Find(int x){ int l=1,r=num,mid; while (l<r){ mid=(l+r)/2; if (b[mid]==x) return mid; if (b[mid]<x) l=mid+1; else r=mid-1; } return l; } int main(){ tt=read(); bin[0]=1; rep(i,1,20) bin[i]=bin[i-1]*2; ans=0; n=read(); m=read(); q=read(); rep(i,1,n) a[i]=read(),b[i]=a[i]; sort(b+1,b+1+n); num=unique(b+1,b+1+n)-b-1; rep(i,1,n) a[i]=Find(a[i]); rep(j,1,m){ int x=read(),y=read(); insert(x,y); insert(y,x); } rep(i,1,n) if (!root[i]) dfs(i); rep(i,1,q){ scanf("%s",ch); if (ch[0]=='Q'){ int x=read()^ans,y=read()^ans,k=read()^ans; ans=b[solve(x,y,k)]; printf("%d ",ans); } else { int x=read()^ans,y=read()^ans; rebuild(x,y); } } return 0; }