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

  1. 5 1
  2. 4 3 2 5 1
  3. 1 2
  4. 7
  5. Q 3 2
  6. Q 2 1
  7. B 2 3
  8. B 1 5
  9. Q 2 1
  10. Q 2 4
  11. Q 2 3

Sample Output

  1. -1
  2. 2
  3. 5
  4. 1
  5. 2

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

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

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

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

  开始有$O(n\log n)$个节点,最后只有$O(n)$个点,所以时间复杂度为$O(n\log 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 << ) - );
  32. const signed long long llf = (signed long long)((1ull << ) - );
  33. const double eps = 1e-;
  34. const int binary_limit = ;
  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 = ;
  43. while(!isdigit((x = getchar())) && x != '-' && x != -);
  44. if(x == -) {
  45. ungetc(x, stdin);
  46. return false;
  47. }
  48. if(x == '-'){
  49. x = getchar();
  50. aFlag = -;
  51. }
  52. for(u = x - ''; isdigit((x = getchar())); u = (u * ) + x - '');
  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(), 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 = ;
  74. SegTreeNode null = SegTreeNode(, &null, &null);
  75.  
  76. inline SegTreeNode* newnode() {
  77. if(top >= Limit) {
  78. return new SegTreeNode(, &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 + )];
  94. rts = new SegTreeNode*[(n + )];
  95. for(int i = ; i <= n; i++)
  96. f[i] = i;
  97. for(int i = ; i <= n; i++) {
  98. rts[i] = null;
  99. update(rts[i], , 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) >> ;
  110. if(idx <= mid) update(node->l, l, mid, idx);
  111. else update(node->r, mid + , 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 -;
  131. if(l == r && k == )
  132. return l;
  133. int ls = node->l->s, mid = (l + r) >> ;
  134. if(k <= ls)
  135. return kth(node->l, l, mid, k);
  136. else
  137. return kth(node->r, mid + , 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)], , 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 + )];
  170. keyer = new int[(n + )];
  171. for(int i = ; i <= n; i++)
  172. readInteger(imp[i]), keyer[imp[i]] = i;
  173. uf = union_found(n, imp);
  174. for(int i = , 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[];
  184. int a, b;
  185. while(q--) {
  186. scanf("%s%d%d", buf, &a, &b);
  187. if(buf[] == 'B') {
  188. uf.unit(a, b);
  189. } else {
  190. int res = uf.query(a, n, b);
  191. if(res == -)
  192. puts("-1");
  193. else
  194. printf("%d\n", keyer[res]);
  195. }
  196. }
  197. }
  198.  
  199. int main() {
  200. init();
  201. solve();
  202. return ;
  203. }

bzoj 2733 永无乡 - 并查集 - 线段树的更多相关文章

  1. BZOJ2733 [HNOI2012]永无乡(并查集+线段树合并)

    题目大意: 在$n$个带权点上维护两个操作: 1)在点$u,v$间连一条边: 2)询问点$u$所在联通块中权值第$k$小的点的编号,若该联通块中的点的数目小于$k$,则输出$-1$: 传送门 上周的模 ...

  2. B20J_2733_[HNOI2012]永无乡_权值线段树合并

    B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...

  3. [bzoj2733][HNOI2012]永无乡_权值线段树_线段树合并

    永无乡 bzoj-2733 HNOI-2012 题目大意:题目链接. 注释:略. 想法: 它的查询操作非常友善,就是一个联通块内的$k$小值. 故此我们可以考虑每个联通块建一棵权值线段树. 这样的话每 ...

  4. 【洛谷P3224】永无乡 并查集+Splay启发式合并

    题目大意:给定 N 个点的图,点有点权,初始有一些无向边,现在有 Q 个询问,每个询问支持动态增加一条无向边连接两个不连通的点和查询第 X 个点所在的联通块中权值第 K 大的是哪个点. 题解:学会了平 ...

  5. BZOJ 2733 永无乡

    splay启发式合并 启发式合并其实就是把集合数量小的合并到集合数量大的里去. 怎么合并呢,直接一个一个插入就行了.. 用并查集维护连通性,find(i)可以找到所在splay的编号 这题好像还可以合 ...

  6. bzoj 2733 永无乡 线段树

    题目: 支持两种操作: 合并两点所在的联通块 查询某点所在联通块内权值第k小. 题解 平衡树启发式合并随便搞一搞就好了. 我写了一个线段树合并 #include <cstdio> #inc ...

  7. BZOJ 3910 并查集+线段树合并

    思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ...

  8. UVA1455 - Kingdom(并查集 + 线段树)

    UVA1455 - Kingdom(并查集 + 线段树) 题目链接 题目大意:一个平面内,给你n个整数点,两种类型的操作:road x y 把city x 和city y连接起来,line fnum ...

  9. 并查集&线段树&树状数组&排序二叉树

    超级无敌巨牛逼并查集(带权并查集)https://vjudge.net/problem/UVALive-4487 带删点的加权并查集 https://vjudge.net/problem/UVA-11 ...

随机推荐

  1. 好吧,我承认我是爱瞎折腾----利用YDUI改变页面UI

    上周恒丰代付接口上线投产后,我做了一个“恒丰代付检查工具”,用途是,当线上调用恒丰代付出现了问题订单时,可以在这个工具页里做相应的弥补. 我项目里其他一些工具页的UI用的是YDUI.YDUI号称是“一 ...

  2. php 门面模式

    1.门面模式为外部提供一个统一的接口,外部调用者不用知道内部的具体复杂业务. 2.如果不使用门面模式,直接访问内部系统,会造成相互直接的耦合关系, 3.想让你的子系统开通哪些,就开通哪些,在门面上开通 ...

  3. Unity shader学习之Alpha Test

    可以在fragment中使用cg的函数--clip来进行透明度测试. 函数定义如下: void clip(float4 x); void clip(float3 x); void clip(float ...

  4. armv8 memory translation table descriptor

    上一节大致给出了descriptor的结构,这篇细致分析各个field: 1) Table Descriptor:stage2中不包含任何的attribute的field,每个level中的descr ...

  5. 设置一个div网页滚动时,使其固定在头部,当页面滚动到距离头部300px时,隐藏该div,另一个div在底部,此时显示;当页面滚动到起始位置时,头部div出现,底部div隐藏

    设置一个div网页滚动时,使其固定在头部,当页面滚动到距离头部300px时,隐藏该div,另一个div在底部,此时显示: 当页面滚动到起始位置时,头部div出现,底部div隐藏 前端代码: <! ...

  6. 20170918-00-(代理ip检验)

    代码集编号 20170918-00 import random #随机数模块 import urllib.request #常用爬虫模块 import time from bs4 import Bea ...

  7. python实现堆栈和队列

    利用python列表实现堆栈和队列 堆栈: 堆栈是一个后进先出的数据结构,其工作方式就像生活中常见到的直梯,先进去的人肯定是最后出. 我们可以设置一个类,用列表来存放栈中的元素的信息,利用列表的app ...

  8. MapReduce的map个数调节 与 Hadoop的FileInputFormat的任务切分原理

    在对日志等大表数据进行处理的时候需要人为地设置任务的map数,防止因map数过小导致集群资源被耗光.可根据大表的数据量大小设置每个split的大小. 例如设置每个split为500M: set map ...

  9. 调用微信JS-SDK配置签名

    前后端进行分开开发: 1:后端实现获取 +++接口凭证:access_token (公众号的全局唯一接口调用凭据) ** GET 获取:https://api.weixin.qq.com/cgi-bi ...

  10. Codeforce 835A - Key races

    Two boys decided to compete in text typing on the site "Key races". During the competition ...