• bzoj 2733 永无乡


    永无乡包含 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

      题目大意 给出n个点和m条边,每个点有个点权,范围为1 ~ n,且没有重复。操作有两种,第一种是联通两个点,第二种是查询点i所在的连通块内第k小的点的编号。

      显然会用到并查集,显然线段树合并。

      然后我来讲讲线段树合并的时间复杂度证明。

      一次线段树合并的实际代价是减少的节点个数。

      开始有$O(nlog n)$个节点,最后只有$O(n)$个点,所以时间复杂度为$O(nlog n)$。

    Code

      1 /**
      2  * bzoj
      3  * Problem#2733
      4  * Accepted
      5  * Time:2352ms
      6  * Memory:26304k
      7  */
      8 #include <iostream>
      9 #include <cstdio>
     10 #include <ctime>
     11 #include <cmath>
     12 #include <cctype>
     13 #include <cstring>
     14 #include <cstdlib>
     15 #include <fstream>
     16 #include <sstream>
     17 #include <algorithm>
     18 #include <map>
     19 #include <set>
     20 #include <stack>
     21 #include <queue>
     22 #include <vector>
     23 #include <stack>
     24 #ifndef WIN32
     25 #define Auto "%lld"
     26 #else
     27 #define Auto "%I64d"
     28 #endif
     29 using namespace std;
     30 typedef bool boolean;
     31 const signed int inf = (signed)((1u << 31) - 1);
     32 const signed long long llf = (signed long long)((1ull << 63) - 1);
     33 const double eps = 1e-6;
     34 const int binary_limit = 128;
     35 #define smin(a, b) a = min(a, b)
     36 #define smax(a, b) a = max(a, b)
     37 #define max3(a, b, c) max(a, max(b, c))
     38 #define min3(a, b, c) min(a, min(b, c))
     39 template<typename T>
     40 inline boolean readInteger(T& u){
     41     char x;
     42     int aFlag = 1;
     43     while(!isdigit((x = getchar())) && x != '-' && x != -1);
     44     if(x == -1) {
     45         ungetc(x, stdin);    
     46         return false;
     47     }
     48     if(x == '-'){
     49         x = getchar();
     50         aFlag = -1;
     51     }
     52     for(u = x - '0'; isdigit((x = getchar())); u = (u * 10) + x - '0');
     53     ungetc(x, stdin);
     54     u *= aFlag;
     55     return true;
     56 }
     57 
     58 typedef class SegTreeNode {
     59     public:
     60         int s;
     61         SegTreeNode *l, *r;
     62         
     63         SegTreeNode():s(0), l(NULL), r(NULL) {        }
     64         SegTreeNode(int s, SegTreeNode* l, SegTreeNode* r):s(s), l(l), r(r) {        }
     65 
     66         inline void pushUp() {
     67             s = l->s + r->s;
     68         }
     69 }SegTreeNode;
     70 
     71 #define Limit 2000000
     72 SegTreeNode pool[Limit];
     73 int top = 0;
     74 SegTreeNode null = SegTreeNode(0, &null, &null);
     75 
     76 inline SegTreeNode* newnode() {
     77     if(top >= Limit) {
     78         return new SegTreeNode(0, &null, &null);
     79     }
     80     pool[top].l = &null, pool[top].r = &null;
     81     return pool + (top++);
     82 }
     83 
     84 #define null &null
     85 
     86 typedef class union_found {
     87     public:
     88         int* f;
     89         SegTreeNode** rts;
     90         
     91         union_found():f(NULL), rts(NULL) {        }
     92         union_found(int n, int* lis) {
     93             f = new int[(const int)(n + 1)];
     94             rts = new SegTreeNode*[(n + 1)];
     95             for(int i = 1; i <= n; i++)
     96                 f[i] = i;
     97             for(int i = 1; i <= n; i++) {
     98                 rts[i] = null;
     99                 update(rts[i], 1, n, lis[i]);
    100             }
    101         }
    102         
    103         void update(SegTreeNode*& node, int l, int r, int idx) {
    104             if(node == null)    node = newnode();
    105             if(l == idx && r == idx) {
    106                 node->s++;
    107                 return;
    108             }
    109             int mid = (l + r) >> 1;
    110             if(idx <= mid)    update(node->l, l, mid, idx);
    111             else update(node->r, mid + 1, r, idx);
    112             node->pushUp(); 
    113         }
    114         
    115         void merge(SegTreeNode*& a, SegTreeNode*& b) {        // Make segment tree b into a.
    116             if(b == null)
    117                 return;
    118             if(a == null) {
    119                 a = b;
    120                 return;
    121             }
    122             a->s += b->s;
    123             merge(a->l, b->l);
    124             merge(a->r, b->r);
    125             a->pushUp();
    126         }
    127         
    128         int kth(SegTreeNode* node, int l, int r, int k) {
    129             if(node == null)
    130                 return -1;
    131             if(l == r && k == 1)
    132                 return l;
    133             int ls = node->l->s, mid = (l + r) >> 1;
    134             if(k <= ls)
    135                 return kth(node->l, l, mid, k);
    136             else
    137                 return kth(node->r, mid + 1, r, k - ls);
    138         }
    139         
    140         int find(int x) {
    141             return (f[x] == x) ? (x) : (f[x] = find(f[x]));
    142         }
    143         
    144         void unit(int fa, int so) {
    145             if(isConnected(fa, so))    return;
    146             int ffa = find(fa);
    147             int fso = find(so);
    148             merge(rts[ffa], rts[fso]);
    149             f[fso] = ffa;
    150         }
    151         
    152         boolean isConnected(int a, int b) {
    153             return find(a) == find(b);
    154         }
    155         
    156         int query(int x, int n, int k) {
    157             return kth(rts[find(x)], 1, n, k);
    158         } 
    159 }union_found;
    160 
    161 int n, m, q;
    162 int* imp;
    163 int* keyer;
    164 union_found uf;
    165 
    166 inline void init() {
    167     readInteger(n);
    168     readInteger(m);
    169     imp = new int[(n + 1)];
    170     keyer = new int[(n + 1)];
    171     for(int i = 1; i <= n; i++)
    172         readInteger(imp[i]), keyer[imp[i]] = i;
    173     uf = union_found(n, imp);
    174     for(int i = 1, a, b; i <= m; i++) {
    175         readInteger(a);
    176         readInteger(b);
    177         uf.unit(a, b);
    178     }
    179 }
    180 
    181 inline void solve() {
    182     readInteger(q);
    183     char buf[10];
    184     int a, b;
    185     while(q--) {
    186         scanf("%s%d%d", buf, &a, &b);
    187         if(buf[0] == 'B') {
    188             uf.unit(a, b);
    189         } else {
    190             int res = uf.query(a, n, b);
    191             if(res == -1)
    192                 puts("-1");
    193             else
    194                 printf("%d
    ", keyer[res]);
    195         }
    196     }
    197 }
    198 
    199 int main() {
    200     init();
    201     solve();
    202     return 0;
    203 }
  • 相关阅读:
    【算法•日更•第五十五期】知识扫盲:什么是卡常数?
    【算法•日更•第五十四期】知识扫盲:什么是operator?
    【算法•日更•第五十三期】知识扫盲:什么是积性函数?
    【原】无脑操作:Webstorm集成Git/Github
    【原】无脑操作:Markdown可以这样玩
    【原】无脑操作:Eclipse + Maven + jFinal + MariaDB 环境搭建
    【原】无脑操作:Centos 7后台运行及终止jar包程序
    【原】无脑操作:TypeScript环境搭建
    【原】无脑操作:Windows下搭建Kafka运行环境
    【原】无脑操作:Chrome浏览器安装Vue.js devtool
  • 原文地址:https://www.cnblogs.com/yyf0309/p/7197566.html
Copyright © 2020-2023  润新知