zoukankan      html  css  js  c++  java
  • [BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)

    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

    HINT

    Source

    Solution

      维护多棵$splay$,当遇到合并操作时把节点个数少的那棵树所有节点,一个一个暴力插到另一棵树里

      整体来看,合并操作最坏情况下会进行$nlogn$次插入,所以合并的总复杂度是$O(nlog^2n)$,查询的总复杂度是$O(qlogn)$

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 struct spaly
      4 {
      5     int c[2], fa, siz, val;
      6     int& operator[] (int x)
      7     {
      8         return c[x];
      9     }
     10 }a[100005];
     11 int root[100005], fa[100005], sta[100005], top;
     12 
     13 int getfa(int x)
     14 {
     15     return fa[x] = x == fa[x] ? x : getfa(fa[x]);
     16 }
     17 
     18 void LDR(int u)
     19 {
     20     if(!u) return;
     21     LDR(a[u][0]), sta[++top] = u, LDR(a[u][1]);
     22 }
     23 
     24 void rotate(int &k, int x)
     25 {
     26     int y = a[x].fa, z = a[y].fa, dy = a[y][1] == x;
     27     if(k == y) k = x;
     28     else a[z][a[z][1] == y] = x;
     29     a[y][dy] = a[x][!dy], a[a[x][!dy]].fa = y;
     30     a[x][!dy] = y, a[y].fa = x, a[x].fa = z;
     31     a[y].siz = a[a[y][0]].siz + a[a[y][1]].siz + 1;
     32 }
     33 
     34 void splay(int &k, int x)
     35 {
     36     while(k != x)
     37     {
     38         int y = a[x].fa, z = a[y].fa;
     39         if(k != y)
     40             if(a[y][1] == x ^ a[z][1] == y) rotate(k, x);
     41             else rotate(k, y);
     42         rotate(k, x);
     43     }
     44     a[x].siz = a[a[x][0]].siz + a[a[x][1]].siz + 1;
     45 }
     46 
     47 void insert(int &k, int x)
     48 {
     49     if(!k)
     50     {
     51         k = x, a[x].siz = 1, a[x][0] = a[x][1] = 0;
     52         return;
     53     }
     54     ++a[k].siz;
     55     if(a[x].val < a[k].val)
     56         insert(a[k][0], x), a[a[k][0]].fa = k;
     57     else insert(a[k][1], x), a[a[k][1]].fa = k;
     58 }
     59 
     60 int find_kth(int k, int x)
     61 {
     62     if(!k) return -1;
     63     if(x <= a[a[k][0]].siz) return find_kth(a[k][0], x);
     64     if(x == a[a[k][0]].siz + 1) return k;
     65     return find_kth(a[k][1], x - a[a[k][0]].siz - 1);
     66 }
     67 
     68 void addedge(int u, int v)
     69 {
     70     if(u == v) return;
     71     if(a[root[u]].siz < a[root[v]].siz)
     72         swap(u, v);
     73     fa[v] = u, LDR(root[v]);
     74     while(top)
     75     {
     76         insert(root[u], sta[top]);
     77         splay(root[u], sta[top--]);
     78     }
     79 }
     80 
     81 int main()
     82 {
     83     int n, m, q, u, v;
     84     char op[5];
     85     scanf("%d%d", &n, &m);
     86     for(int i = 1; i <= n; ++i)
     87         scanf("%d", &a[i].val);
     88     for(int i = 1; i <= n; ++i)
     89         root[i] = fa[i] = i, a[i].siz = 1;
     90     while(m--)
     91     {
     92         scanf("%d%d", &u, &v);
     93         addedge(getfa(u), getfa(v));
     94     }
     95     scanf("%d", &q);
     96     while(q--)
     97     {
     98         scanf("%s%d%d", op, &u, &v);
     99         if(op[0] == 'B') addedge(getfa(u), getfa(v));
    100         else printf("%d
    ", find_kth(root[getfa(u)], v));
    101     }
    102     return 0;
    103 }
    View Code
  • 相关阅读:
    mac 10.15.7 修改PATH
    oc 属性类型一般用法
    ubuntu解压zip文件名乱码
    telnet 退出
    docker 根据容器创建镜像
    mac android adb device 没有显示设备
    Yii2 查看所有的别名 alias
    Yii2 App Advanced 添加 .gitignore
    ubuntu 18.04 搜狗突然就提示乱码
    An error occured while deploying the file. This probably means that the app contains ARM native code and your Genymotion device cannot run ARM instructions. You should either build your native code to
  • 原文地址:https://www.cnblogs.com/CtrlCV/p/5621938.html
Copyright © 2011-2022 走看看