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\n", find_kth(root[getfa(u)], v));
101     }
102     return 0;
103 }

View Code

转载于:https://www.cnblogs.com/CtrlCV/p/5621938.html

[BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)相关推荐

  1. BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]

    2733: [HNOI2012]永无乡 题意:加边,询问一个连通块中k小值 终于写了一下splay启发式合并 本题直接splay上一个节点对应图上一个点就可以了 并查集维护连通性 合并的时候,把siz ...

  2. BZOJ[2733][HNOI2012]永无乡 Splay启发式合并

    题目链接 题目大意及线段树合并解法在这里 每合并两个点,将它俩启发式合并 启发式合并,即把小的暴力往大的那里插 说按前序遍历插复杂度会极其优越?? 第k大是平衡树基本操作 代码如下: #include ...

  3. 【BZOJ 2733】 [HNOI2012]永无乡|Splay启发式合并

    代码能力太弱 #include <cstdio> #include <iostream> #include <algorithm> using namespace ...

  4. P3224 [HNOI2012]永无乡 FHQ-Treap 启发式合并

    题意: B x y B\ x\ y B x y 表示在岛 x x x 与岛 y y y 之间修建一座新桥. Q x k Q\ x\ k Q x k 表示询问当前与岛 x x x 连通的所有岛中第 k ...

  5. [Bzoj2733][Hnoi2012] 永无乡(BST)(Pb_ds tree)

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 4108  Solved: 2195 [Submit][Sta ...

  6. bzoj2733 [HNOI2012]永无乡

    http://www.elijahqi.win/2018/02/16/bzoj2733/ 题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n ...

  7. BZOJ 2733: [HNOI2012]永无乡 启发式合并treap

    2733: [HNOI2012]永无乡 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  8. bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 3850  Solved: 2061 [Submit][Sta ...

  9. P3224 [HNOI2012]永无乡(并查集+权值线段树合并/平衡树)

    [HNOI2012]永无乡 Code1 权值线段树天然支持merge,线段树上二分求第k小 #include<bits/stdc++.h>using namespace std; usin ...

最新文章

  1. Delphi 调用webservice接口
  2. 阿里最新论文解读:考虑时空域影响的点击率预估模型DSTN
  3. 光缆能预警地震?谷歌做到了!毫秒级反应速度,140万公里海缆有望成为报警器...
  4. php 效率最高的递归,PHP 递归效率分析_PHP教程 - microtime
  5. Hbase:原理和设计
  6. statuml怎么添加用户_UML课后习题答案
  7. “一个人自修没感觉!”
  8. UI实用素材模板|可临摹学习的控制面板
  9. Mysql学习总结(73)——MySQL 查询A表存在B表不存在的数据SQL总结
  10. POJ 3253 Fence Repair 贪心
  11. cesium +vue项目怎么运行
  12. python绘制相频特性曲线_python skimage图像处理(二)
  13. IBM小型机安装AIX系统
  14. 简谈PCB设计软件对比
  15. python添加环境变量代码_Maya中的PYTHONPATH 环境变量
  16. 简洁开源的一款导航网站源码
  17. 节理玫瑰花图怎么画_如何用Excel绘制节理玫瑰花图、水系玫瑰花图?如何将CAD属性平面角智能转化为方向角?...
  18. uni-app简单实现手写签名
  19. (七)Zabbix实现微信报警通知
  20. 计算机应用基础南京廖华,《计算机应用基础》习题及答案

热门文章

  1. 西华大学c语言考试题,西华大学C语言程序设计复习题
  2. layUI日期框回调函数
  3. 关掉云存储后噪声 海康摄像头_万物互联 海量数据如何实现更好的存储和应用...
  4. 计算机监控防误,计算机监控防误操作系统专利_专利申请于2007-10-25_专利查询 - 天眼查...
  5. springboot 2中文手册_熬夜整理了一套最新版的Java面试题和开发手册(附答案)...
  6. Python入门--创建类的对象
  7. angular学习笔记
  8. k_means算法+python实现
  9. 2019第十届蓝桥杯B组C++省赛E题迷宫--BFS(倒搜)
  10. UnityShader14:透明效果实现(上)