zoukankan      html  css  js  c++  java
  • bzoj2733: [HNOI2012]永无乡 启发式合并

    地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733

    题目:

    2733: [HNOI2012]永无乡

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 4059  Solved: 2167
    [Submit][Status][Discuss]

    Description

    永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。 
     

    Input

    输入文件第一行是用空格隔开的两个正整数 n 和 m,分别 表示岛的个数以及一开始存在的桥数。接下来的一行是用空格隔开的 n 个数,依次描述从岛 1 到岛 n 的重要度排名。随后的 m 行每行是用空格隔开的两个正整数 ai 和 bi,表示一开始就存 在一座连接岛 ai 和岛 bi 的桥。后面剩下的部分描述操作,该部分的第一行是一个正整数 q, 表示一共有 q 个操作,接下来的 q 行依次描述每个操作,操作的格式如上所述,以大写字母 Q 或B 开始,后面跟两个不超过 n 的正整数,字母与数字以及两个数字之间用空格隔开。 对于 20%的数据 n≤1000,q≤1000 
     
    对于 100%的数据 n≤100000,m≤n,q≤300000 
     

    Output

    对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表 示所询问岛屿的编号。如果该岛屿不存在,则输出-1。 
     

    Sample Input

    5 1
    4 3 2 5 1
    1 2
    7
    Q 3 2
    Q 2 1
    B 2 3
    B 1 5
    Q 2 1
    Q 2 4
    Q 2 3

    Sample Output

    -1
    2
    5
    1
    2
     
    思路:
      启发式合并。
      1 /**************************************************************
      2     Problem: 2733
      3     User: weeping
      4     Language: C++
      5     Result: Accepted
      6     Time:4908 ms
      7     Memory:4436 kb
      8 ****************************************************************/
      9  
     10 #include <bits/stdc++.h>
     11  
     12 using namespace std;
     13  
     14 #define lc ch[x][0]
     15 #define rc ch[x][1]
     16  
     17 int n,m,q,f[100005];
     18  
     19 int fd(int x)
     20 {
     21     return f[x]==x?x:f[x]=fd(f[x]);
     22 }
     23  
     24 struct SplayTree
     25 {
     26  
     27     const static int maxn = 1e5 + 15;
     28  
     29     int tot,root,ch[maxn][2], key[maxn], val[maxn], sz[maxn], rev[maxn], fa[maxn];
     30  
     31     inline void init( int x, int ky, int v = 0, int par = 0 )
     32     {
     33         lc=rc=0, fa[x]= par, key[x] = ky, val[x] = v, sz[x] = 1, rev[x] = 0;
     34     }
     35  
     36     inline void init()
     37     {
     38         init( 0, 0, 0 );
     39         sz[0] = 0;
     40         tot = root = 0 ;
     41     }
     42  
     43     inline void push_up(int x)
     44     {
     45         sz[x] = sz[lc] + sz[rc] + 1;
     46     }
     47  
     48     inline void reverse(int x)
     49     {
     50         rev[x] ^= 1, swap( lc, rc);
     51     }
     52  
     53     inline void push_down(int x)
     54     {
     55         if(rev[x])
     56         {
     57             if(lc)  reverse(lc);
     58             if(rc)  reverse(rc);
     59             rev[x] = 0;
     60         }
     61     }
     62  
     63     void rotate( int x)
     64     {
     65         int f = fa[x], gf = fa[f];
     66         int t1 = (ch[f][1] == x), t2 = (ch[gf][1] == f);
     67         if( gf ) ch[gf][t2] = x;
     68         fa[x] = gf, ch[f][t1] = ch[x][1^t1], fa[ch[f][t1]] = f;
     69         ch[x][t1^1] = f, fa[f] = x;
     70         push_up( f ), push_up( x );
     71     }
     72  
     73     void splay( int x, int tar )
     74     {
     75         for(int f = fa[x], gf = fa[f]; f != tar; rotate(x), f = fa[x], gf = fa[f])
     76         if(gf != tar)
     77             rotate( ((ch[f][1] == x) == (ch[gf][1] == f) )? f: x);
     78         if( !tar ) root = x;
     79     }
     80  
     81     void insert( int ky, int v)
     82     {
     83         int x = root, ls = root;
     84         while(x)
     85         {
     86             push_down(x);
     87             sz[x] ++, ls = x;
     88             x = ch[x][ky > key[x]];
     89         }
     90         init( ++tot, ky, v, ls);
     91         ch[ls][ky > key[ls]] = tot;
     92         splay( tot, 0);
     93     }
     94  
     95     int find( int ky)
     96     {
     97         int x = root;
     98         while(x)
     99         {
    100             push_down(x);
    101             if(key[x] == ky) break;
    102             x = ch[x][ky > key[x]];
    103         }
    104         if(x)   splay(x,0);
    105         else x = -1;
    106         return x;
    107     }
    108  
    109     // Delete Root
    110     void Delete()
    111     {
    112         if( !ch[root][0] )
    113         {
    114             fa[ ch[root][1] ] = 0 ;
    115             root = ch[root][1];
    116         }
    117         else
    118         {
    119             int cur = ch[root][0];
    120             while( ch[cur][1] ) cur = ch[cur][1];
    121             splay( cur, root );
    122             ch[cur][1] = ch[root][1];
    123             root = cur, fa[cur] = 0, fa[ch[root][1]] = root;
    124             push_up( root );
    125         }
    126     }
    127  
    128     int kth( int k)
    129     {
    130         int x = root;
    131         if(sz[x] < k) return -1;
    132         while(x)
    133         {
    134             push_down(x);
    135             if(k == sz[lc] + 1) break;
    136             if(k > sz[lc])
    137                 k -= sz[lc] + 1, x = rc;
    138             else
    139                 x = lc;
    140         }
    141         if(x)   splay(x,0);
    142         else x = -1;
    143         return x;
    144     }
    145  
    146     int pred( void)
    147     {
    148         int x = root;
    149         if(!x || !lc)   return -1;
    150         x = lc;
    151         while(rc)    push_down(x), x = rc;
    152         splay( x, 0);
    153         return x;
    154     }
    155  
    156     int succ( void)
    157     {
    158         int x = root;
    159         if(!x || !rc) return -1;
    160         x = rc;
    161         while(lc)   push_down(x), x = lc;
    162         splay( x, 0);
    163         return x;
    164     }
    165  
    166     void debug( int x )
    167     {
    168         if( !x ) return;
    169         if(lc) debug( lc );
    170         printf("%d ", key[x] );
    171         if(rc) debug( rc );
    172     }
    173  
    174     void qinsert(int y)
    175     {
    176         int x = root, ls = root, ky = key[y];
    177         while(x)
    178             ls = x, x = ch[x][ky > key[x]];
    179         x = ls;
    180         ch[x][ky > key[x]] = y,fa[y] = x, sz[y] = 1;
    181         splay(y, 0);
    182     }
    183  
    184     void qmerge(int x)
    185     {
    186         if(!x) return;
    187         int tl = lc, tr = rc;
    188         lc  = rc = 0;
    189         qmerge(tl);
    190         qinsert(x);
    191         qmerge(tr);
    192     }
    193     void merge(int u,int v)
    194     {
    195         if(u == v) return ;
    196         if(sz[u]>sz[v]) swap(u,v);
    197         f[u] = v, splay( v, 0);
    198         qmerge(u);
    199     }
    200 } sp;
    201  
    202  
    203 int main(void)
    204 {
    205     scanf("%d%d",&n,&m);
    206     for(int i=1,x;i<=n;i++)
    207         scanf("%d",&x),f[i]=i,sp.key[i]=x,sp.sz[i]=1;
    208     for(int i=1,u,v;i<=m;i++)
    209         scanf("%d%d",&u,&v),sp.merge(fd(u),fd(v));
    210     scanf("%d",&q);
    211     char op[5];
    212     for(int i=1,x,y;i<=q;i++)
    213     {
    214         scanf("%s%d%d",op,&x,&y);
    215         if(op[0]=='B')
    216             sp.merge(fd(x),fd(y));
    217         else
    218             sp.splay(x,0),printf("%d
    ",sp.kth(y));
    219     }
    220     return 0;
    221 }
  • 相关阅读:
    Leetcode 16.25 LRU缓存 哈希表与双向链表的组合
    Leetcode437 路径总和 III 双递归与前缀和
    leetcode 0404 二叉树检查平衡性 DFS
    Leetcode 1219 黄金矿工 暴力回溯
    Leetcode1218 最长定差子序列 哈希表优化DP
    Leetcode 91 解码方法
    Leetcode 129 求根到叶子节点数字之和 DFS优化
    Leetcode 125 验证回文串 双指针
    Docker安装Mysql记录
    vmware虚拟机---Liunx配置静态IP
  • 原文地址:https://www.cnblogs.com/weeping/p/7662458.html
Copyright © 2011-2022 走看看