bzoj 2733 Splay 启发式合并,名次树
题意:给定一个带点权的无向图,有两种操作:
1、将两个连通分量合并。
2、查询某个连通分量里的第K大点。
题解:
用并查集维护连通关系,一开始建立n棵splay树,然后不断合并,查询。
处理技巧:
1、每个顶点u所在的Splay就是T[find(u)]。
2、每个顶点在树中对应的节点编号就是该顶点的编号。
1 #include <cstdio> 2 #include <iostream> 3 #define maxn 100110 4 using namespace std; 5 6 7 int key[maxn], pre[maxn], son[maxn][2], siz[maxn], ntot; 8 struct Splay { 9 int root; 10 Splay():root(0){} 11 void update( int nd ) { 12 siz[nd] = siz[son[nd][0]] + siz[son[nd][1]] + 1; 13 } 14 void rotate( int nd, int d ) { 15 int p = pre[nd]; 16 int s = son[nd][!d]; 17 int ss = son[s][d]; 18 19 son[nd][!d] = ss; 20 son[s][d] = nd; 21 if( p ) son[p][ nd==son[p][1] ] = s; 22 else root = s; 23 24 pre[nd] = s; 25 pre[s] = p; 26 if( ss ) pre[ss] = nd; 27 28 update( nd ); 29 update( s ); 30 } 31 void splay( int nd, int top=0 ) { 32 while( pre[nd]!=top ) { 33 int p = pre[nd]; 34 int nl = nd==son[p][0]; 35 if( pre[p]==top ) { 36 rotate( p, nl ); 37 } else { 38 int pp = pre[p]; 39 int pl = p==son[pp][0]; 40 if( nl==pl ) { 41 rotate( pp, pl ); 42 rotate( p, nl ); 43 } else { 44 rotate( p, nl ); 45 rotate( pp, pl ); 46 } 47 } 48 } 49 } 50 int initnode( int nd, int k, int p ) { 51 key[nd] = k; 52 pre[nd] = p; 53 son[nd][0] = son[nd][1] = 0; 54 siz[nd] = 1; 55 return nd; 56 } 57 void insert( int k, int nnd ) { 58 if( !root ) { 59 root = initnode(nnd,k,0); 60 return; 61 } 62 int nd = root; 63 while( son[nd][ k>key[nd] ] ) 64 nd = son[nd][ k>key[nd] ]; 65 son[nd][ k>key[nd] ] = initnode(nnd,k,nd); 66 update( nd ); 67 splay( nd ); 68 } 69 int nth( int n ) { 70 int nd = root; 71 while( 1 ) { 72 int ls = siz[son[nd][0]]; 73 if( n<=ls ) { 74 nd = son[nd][0]; 75 } else if( n>=ls+2 ) { 76 nd = son[nd][1]; 77 n -= ls+1; 78 } else { 79 break; 80 } 81 } 82 splay(nd); 83 return nd; 84 } 85 inline int size() { return siz[root]; } 86 static void join( Splay &T , int snd ) { 87 if( !snd ) return; 88 join( T, son[snd][0] ); 89 join( T, son[snd][1] ); 90 T.insert( key[snd], snd ); 91 } 92 }; 93 94 int n, m, q; 95 int fa[maxn]; 96 Splay T[maxn]; 97 98 int find( int a ) { 99 return a==fa[a] ? a : fa[a]=find(fa[a]); 100 } 101 102 void join( int a, int b ) { 103 if( find(a)==find(b) ) return; 104 if( T[find(a)].size() > T[find(b)].size() ) swap(a,b); 105 Splay::join( T[find(b)], T[find(a)].root ); 106 fa[find(a)] = find(b); 107 } 108 109 int main() { 110 scanf( "%d%d", &n, &m ); 111 for( int i=1,w; i<=n; i++ ) { 112 scanf( "%d", &w ); 113 fa[i] = i; 114 T[i].insert( w, i ); 115 } 116 for( int i=1,u,v; i<=m; i++ ) { 117 scanf( "%d%d", &u, &v ); 118 join(u,v); 119 } 120 scanf( "%d", &q ); 121 while( q-- ) { 122 char ch[2]; 123 int a, b; 124 scanf( "%s%d%d", ch, &a, &b ); 125 if( ch[0]=='B' ) { 126 join(a,b); 127 } else { 128 if( !(1<=b&&b<=T[find(a)].size()) ) printf( "-1\n" ); 129 else printf( "%d\n", T[find(a)].nth(b) ); 130 } 131 } 132 }