• 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
    " );
    129             else printf( "%d
    ", T[find(a)].nth(b) );
    130         }
    131     }
    132 }
    View Code
  • 相关阅读:
    POJ 3292 Semi-prime H-numbers (素数筛法变形)
    POJ 1845 Sumdiv (整数拆分+等比快速求和)
    POJ 2635 The Embarrassed Cryptographer(大数求余)
    POJ 2115 C Looooops (扩展欧几里德 + 线性同余方程)
    poj3071
    poj2486
    poj1947
    POJ 1159
    POJ 1845
    poj3282
  • 原文地址:https://www.cnblogs.com/idy002/p/4275812.html
Copyright © 2020-2023  润新知