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 }
View Code

 

posted @ 2015-02-05 19:51  idy002  阅读(400)  评论(0编辑  收藏  举报