2733: [HNOI2012]永无乡

Time Limit: 10 Sec  Memory Limit: 128 MB

Submit: 4190  Solved: 2226

[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

题解

这道题需要我们合并各个联通块并询问第k大
询问第k大可以用splay实现,但如何合并呢?
将两棵中较小的那一棵的节点全部取出来插入另一颗

这么暴力不会超时么?
我们最多合并n - 1次,每次尽量将相同大小的联通块合并,总共最多插入(n / 2) * logn次
所以总的复杂度O(nlog^2n)
【打个splay都打错调了半天= =】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define isr(u) (e[e[u].f].ch[1] == u)
#define sizl(u) (e[e[u].ch[0]].siz)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1;char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
return out * flag;
}
int rt = 0,pre[maxn],n,m,q;
struct node{int v,f,ch[2],siz;}e[maxn];
int find(int u) {return u == pre[u] ? u : pre[u] = find(pre[u]);}
inline void pu_p(int u){e[u].siz = e[e[u].ch[0]].siz + 1 + e[e[u].ch[1]].siz;}
inline void spin(int u){
int s = isr(u),fa = e[u].f;
e[u].f = e[fa].f;
if (e[fa].f) e[e[fa].f].ch[isr(fa)] = u;
e[fa].ch[s] = e[u].ch[s ^ 1];
if (e[u].ch[s ^ 1]) e[e[u].ch[s ^ 1]].f = fa;
e[fa].f = u;
e[u].ch[s ^ 1] = fa;
pu_p(fa); pu_p(u);
}
inline void splay(int u){
while (e[u].f){
if (!e[e[u].f].f) spin(u);
else if (isr(u) ^ isr(e[u].f)) spin(u),spin(u);
else spin(e[u].f),spin(u);
}
rt = u;
}
inline void insert(int p){
int u = rt,f = 0,v = e[p].v;
while(u) f = u,u = v < e[u].v ? e[u].ch[0] : e[u].ch[1];
e[f].ch[v > e[f].v] = p; e[p].f = f;
splay(p);
}
inline int Kth(int u,int k){
splay(u); int Lsiz = 0;
while (u){
int t = Lsiz + sizl(u);
if (k <= t) u = e[u].ch[0];
else if (k == t + 1) return u;
else Lsiz = t + 1,u = e[u].ch[1];
}
return -1;
}
inline void order(int u){
int l = e[u].ch[0],r = e[u].ch[1];
e[u].siz = 1; e[u].ch[0] = e[u].ch[1] = e[u].f = 0;
if (l) order(l);
insert(u);
if (r) order(r);
}
inline void Merge(int u,int v){
if (u == v) return;
pre[v] = u;
splay(v); splay(u);
if (e[u].siz < e[v].siz) swap(u,v);
rt = u;
order(v);
}
int main()
{
int fa,fb,x,k;
char c;
n = read(); m = read();
REP(i,n) e[i].v = read(),e[i].siz = 1,pre[i] = i,e[i].ch[0] = e[i].ch[1] = e[i].f = 0;
REP(i,m) fa = find(read()),fb = find(read()),Merge(fa,fb);
q = read();
REP(i,q){
c = getchar();
while (c != 'B' && c != 'Q') c = getchar();
if (c == 'B'){
fa = find(read()); fb = find(read());
Merge(fa,fb);
}
else { x = find(read()); k = read(); printf("%d\n",Kth(x,k));}
}
return 0;
}


BZOJ2733 永无乡 【splay启发式合并】的更多相关文章

  1. 【BZOJ-2733】永无乡 Splay+启发式合并

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2048  Solved: 1078[Submit][Statu ...

  2. [BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)

    Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...

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

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

  4. 【洛谷3224/BZOJ2733】[HNOI2012]永无乡 (Splay启发式合并)

    题目: 洛谷3224 分析: 这题一看\(n\leq100000\)的范围就知道可以暴力地用\(O(nlogn)\)数据结构乱搞啊-- 每个联通块建一棵Splay树,查询就是Splay查询第k大的模板 ...

  5. 【BZOJ 2733】【HNOI 2012】永无乡 Splay启发式合并

    启发式合并而已啦,, 调试时发现的错误点:insert后没有splay,把要拆开的树的点插入另一个树时没有把ch[2]和fa设为null,找第k大时没有先减k,,, 都是常犯的错误,比赛时再这么粗心就 ...

  6. 洛谷.3224.[HNOI2012]永无乡(Splay启发式合并)

    题目链接 查找排名为k的数用平衡树 合并时用启发式合并,把size小的树上的所有节点插入到size大的树中,每个节点最多需要O(logn)时间 并查集维护连通关系即可 O(nlogn*insert t ...

  7. 【bzoj2733】[HNOI2012]永无乡 Treap启发式合并

    题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...

  8. BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)

    不难...treap + 启发式合并 + 并查集 搞搞就行了 --------------------------------------------------------------------- ...

  9. bzoj2733 永无乡 splay树的启发式合并

    https://vjudge.net/problem/HYSBZ-2733 给一些带权点,有些点是互相连通的, 然后给出2种操作,在两点间加一条边,或者询问一个点所在的连通块内的第k小值的编号 并查集 ...

  10. 【BZOJ2733】[HNOI2012] 永无乡(启发式合并Splay)

    点此看题面 大致题意: 给你一张图,其中每个点有一个权值,有两种操作:在两点之间连一条边,询问一个点所在联通块第\(k\)小的权值. 平衡树 看到第\(k\)小,应该不难想到平衡树. 为了练习\(Sp ...

随机推荐

  1. python2 - 列表

    列表 a = [1,2,3,4,5,6,7] a[0:4:1]//正向索引 a[-1:-2:-1]//反向索引 列表添加 a = [1, 2] b = [3, 4] +:a + b//把a和b连接,重 ...

  2. 131. 分割回文串 javascript实现

    给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回 s 所有可能的分割方案. 示例: 输入: "aab" 输出: [ ["aa",&quo ...

  3. 廖雪峰git笔记

    查看本地机子的在Git上的名字和邮箱:git config user.namegit config user.email 对所有仓库指定相同的用户名和Email地址:git config --glob ...

  4. RyuBook1.0案例三:REST Linkage

    REST Linkage 该小结主要介绍如何添加一个REST Link 函数 RYU本身提供了一个类似WSGI的web服务器功能.借助这个功能,我们可以创建一个REST API. 基于创建的REST ...

  5. Kafka安装之三 spring-kafka实践

    一.spring-kafka配置详解 1.1 要是用spring-kafka 我们首先要在pom要.xml中引入spring-kafka包 <dependencies> <depen ...

  6. Dubbo背景和简介

    转载出处 Dubbo开始于电商系统,因此在这里先从电商系统的演变讲起. 单一应用框架(ORM) 当网站流量很小时,只需一个应用,将所有功能如下单支付等都部署在一起,以减少部署节点和成本. 缺点:单一的 ...

  7. hashlib模块使用详情

    python常用模块目录 一:hashlib简介 1.什么叫hash:hash是一种算法(不同的hash算法只是复杂度不一样)(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224 ...

  8. python基础知识-03-字符串

    python其他知识目录 1.for循环遍历字符串中单个字符 s_str="mcw" for i in s_str: print(i) -----------结果: m c w 2 ...

  9. LCA(Tarjan算法)模板

    一.查询一组的LCA Nearest Common Ancestors A rooted tree is a well-known data structure in computer science ...

  10. 进击的SDN

    SDN是什么? 不再是OSI七层模型,全新的SDN三层模型. 起源于斯坦福大学博士生领导的一个项目Ethane:通过一个集中式控制器(NOX),网络管理员可以定义基于网络流的控制策略,并将这个策略用于 ...