题意:
n个节点,每个节点有个权值,初始时有m次连通两点的操作,接下来有q次操作,每次可以连通两个点或求某个点所在连通块权值第k小的节点编号。n,m≤100000,q≤300000
题解:
treap启发式合并,就是暴力将小的树拆了插到大的树里,均摊复杂度O(log22n)。由于本弱用的是treap,不能维护fa数组,所以要并查集维护根节点。如果是splay就不用。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdlib> 5 #include <queue> 6 #define inc(i,j,k) for(int i=j;i<=k;i++) 7 #define maxn 100500 8 using namespace std; 9 10 int fa[maxn],rt[maxn],ch[maxn][2],v[maxn],sz[maxn],rnd[maxn]; 11 void update(int x){ 12 sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; 13 } 14 void rot(int &x,bool lr){ 15 if(!x)return; int a=ch[x][lr]; ch[x][lr]=ch[a][!lr]; ch[a][!lr]=x; 16 update(x); update(a); x=a; 17 } 18 void insert(int &x,int y){ 19 if(!x){x=y; return;} 20 if(v[y]<v[x])insert(ch[x][0],y);else insert(ch[x][1],y); update(x); 21 if(ch[x][0]&&rnd[ch[x][0]]<rnd[x])rot(x,0); 22 if(ch[x][1]&&rnd[ch[x][1]]<rnd[x])rot(x,1); 23 } 24 int find(int x,int k){ 25 if(sz[x]<k)return -1; 26 if(sz[ch[x][0]]==k-1)return x; 27 if(sz[ch[x][0]]<k-1)return find(ch[x][1],k-sz[ch[x][0]]-1); 28 if(sz[ch[x][0]]>k-1)return find(ch[x][0],k); 29 } 30 queue <int> q; 31 int fd(int x){return x==fa[x]?x:fa[x]=fd(fa[x]);} 32 void merge(int xx,int yy){ 33 int x=fd(xx),y=fd(yy); if(x==y)return; if(sz[rt[x]]>sz[rt[y]])swap(x,y); 34 fa[x]=y; while(! q.empty())q.pop(); q.push(rt[x]); y=rt[y]; 35 while(! q.empty()){ 36 int z=q.front(); q.pop(); sz[z]=1; 37 if(ch[z][0])q.push(ch[z][0]); if(ch[z][1])q.push(ch[z][1]); 38 ch[z][0]=ch[z][1]=0; insert(y,z); 39 } 40 rt[fa[x]]=y; 41 } 42 inline int read(){ 43 char ch=getchar(); int f=1,x=0; 44 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} 45 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 46 return f*x; 47 } 48 int n,m; 49 int main(){ 50 n=read(); m=read(); 51 inc(i,1,n) 52 v[i]=read(),ch[i][0]=ch[i][1]=0,rnd[i]=rand(),fa[i]=rt[i]=i,sz[i]=1; 53 inc(i,1,m){int a=read(),b=read(); merge(a,b);} 54 m=read(); char opt[3]; 55 inc(i,1,m){ 56 scanf("%s",opt); 57 if(opt[0]=='Q'){ 58 int a=read(),b=read(); printf("%d ",find(rt[fd(a)],b)); 59 } 60 if(opt[0]=='B'){ 61 int a=read(),b=read(); merge(a,b); 62 } 63 } 64 return 0; 65 }
201608608