【题解】永无乡 [HNOI2012] [BZOJ2733] [P3224]


【题目描述】

永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 \(1\) 到 \(n\) 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 \(a\) 出发经过若干座(包括 \(0\) 座)桥可以到达岛 \(b\) ,则称岛 \(a\) 和岛 \(b\) 是连通的。

现在有两种操作:

\(B\) \(x\) \(y\) \(:\) 表示在岛 \(x\) 与岛 \(y\) 之间修建一座新桥。

\(Q\) \(x\) \(k\) \(:\) 表示询问当前与岛 \(x\) 连通的所有岛中第 \(k\) 重要的是哪座岛,即所有与岛 \(x\) 连通的岛中重要度排名第 \(k\) 小的岛是哪座,请你输出那个岛的编号。

【输入】

第一行两个正整数 \(n\) 和 \(m\) ,分别表示岛的个数以及一开始存在的桥数。

接下来的一行有 \(n\) 个数,依次描述从岛 \(1\) 到岛 \(n\) 的重要度。

随后的 \(m\) 行每行两个正整数 \(a_i​\) 和 \(b_i\)​ ,表示一开始就存在一座连接岛 \(a_i\) 和岛 \(b_i\)​ 桥。

后面第一行一个正整数 \(q\),表示一共有 \(q\) 个操作,接下来的 \(q\) 表示 \(q\) 个操作。

【输出】

对于每个 \(Q\) \(x\) \(k\) 的操作依次输出一行,其中包含一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出 \(-1\) 。

【样例】

输入:
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 样例输出:
-1
2
5
1
2

【数据范围】

\(20\%\) \(1 \leqslant n \leqslant 1000,1 \leqslant q \leqslant 1000\)

\(100\%\) \(1 \leqslant n \leqslant 1e5,m \leqslant n,1 \leqslant q \leqslant 3e5\)


【分析】

不会线段树的先到隔壁去逛逛:线段树详解(全)

一道线段树合并的好题

并查集维护各个连通块,每个块都建立一棵权值线段树,在合并两个块的同时,将它们的线段树也进行合并。那么原问题就变成了在一棵线段树中求第 \(k\) 小,而这个是权值线段树的基本操作。

【Code】

#include<algorithm>
#include<cstdio>
#define mid (L+R>>1)
#define pl tr[p].lp
#define pr tr[p].rp
#define Re register int
#define F(a,b) for(i=a;i<=b;++i)
using namespace std;
const int N=2e5+3;char c;
int x,y,i,n,m,cnt,f[N],id[N],pt[N];//pt[i]表示离散化后i这个位置所对应的权值树根的编号
struct QAQ{int g,lp,rp;}tr[N<<5];//权值树,保守开一个32*N
inline void in(Re &x){//【快读】自己动手,丰衣足食...
x=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
inline int build(Re L,Re R,Re x){//开一个空的权值树
Re p=++cnt;++tr[p].g;//【动态开点】
if(L==R)return p;
if(x<=mid)pl=build(L,mid,x);
else pr=build(mid+1,R,x);
return p;
}
inline int merge(Re p,Re q){//【线段树合并】
if(!p)return q;if(!q)return p;
//当需要合并的点的其中一个编号为0时 (即为空),返回另一个编号
tr[p].g+=tr[q].g,p;//把q合并到p上面去
pl=merge(pl,tr[q].lp);//分别合并左子树,右子树
pr=merge(pr,tr[q].rp);
return p;
}
inline int ask(Re p,Re L,Re R,Re k){//查询
if(L==R)return id[R];//边界:L==R
Re tmp=tr[pl].g;//计算左子树共有多少个数字
if(tmp>=k)return ask(pl,L,mid,k);//左子树已经超过k个,说明第k小在左子树里面
else return ask(pr,mid+1,R,k-tmp);//左子树不足k个,应该在右子树中找第(k-tmp)小
}
inline int find(Re x){if(x!=f[x])f[x]=find(f[x]);return f[x];}
int main(){
in(n),in(m);
F(1,n)in(x),id[x]=i,f[i]=i,pt[i]=build(1,n,x);
//用id[x]表示重要度为x的点的编号,给每个点建一棵树
while(m--){//初始的桥要连起来
in(x),in(y),x=find(x),y=find(y);
merge(pt[x],pt[y]),f[y]=f[x];//注意这里merge(pt[],pt[])和f[]=f[]中x,y的顺序要相反
}
in(m);
while(m--){
scanf(" %c",&c),in(x),in(y),x=find(x);
if(c=='B')y=find(y),merge(pt[x],pt[y]),f[y]=f[x];
else{
if(tr[pt[x]].g<y)printf("-1\n");//如果总个数都小于y,说明没有第y大的数,直接输出-1
else printf("%d\n",ask(pt[x],1,n,y));
}
}
}

【题解】永无乡 [HNOI2012] [BZOJ2733] [P3224]的更多相关文章

  1. 【BZOJ2733】永无乡[HNOI2012](splay启发式合并or线段树合并)

    题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被 ...

  2. 洛谷P3224 永无乡 [HNOI2012] 线段树/splay/treap

    正解:线段树合并 解题报告: 传送门! 这题也是有很多解法,eg:splay,treap,... 然而我都不会我会学的QAQ! 反正今天就只讲下线段树合并怎么做QAQ 首先看到这样子的说第k重要的是什 ...

  3. P3224 [HNOI2012]永无乡 题解

    P3224 [HNOI2012]永无乡 题解 题意概括 有若干集合,每个集合最初包含一个值,和一个编号1~n.两个操作:合并两个集合,查询包含值x的集合中第k大值最初的集合编号. 思路 维护集合之间关 ...

  4. bzoj2733 / P3224 [HNOI2012]永无乡(并查集+线段树合并)

    [HNOI2012]永无乡 每个联通块的点集用动态开点线段树维护 并查集维护图 合并时把线段树也合并就好了. #include<iostream> #include<cstdio&g ...

  5. 线段树合并+并查集 || BZOJ 2733: [HNOI2012]永无乡 || Luogu P3224 [HNOI2012]永无乡

    题面:P3224 [HNOI2012]永无乡 题解: 随便写写 代码: #include<cstdio> #include<cstring> #include<iostr ...

  6. 洛谷 P3224 [HNOI2012]永无乡 解题报告

    P3224 [HNOI2012]永无乡 题目描述 永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 ...

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

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

  8. bzoj2733: [HNOI2012]永无乡 启发式合并

    地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 题目: 2733: [HNOI2012]永无乡 Time Limit: 10 Sec   ...

  9. bzoj2733: [HNOI2012]永无乡 线段树合并

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

随机推荐

  1. python 配置文件 ConfigParser模块

    ConfigParser模块 用于生成和修改常见配置文档,当前模块的名称在 python 3.x 版本中变更为 configparser. 来看一个好多软件的常见文档格式如下 [DEFAULT] Se ...

  2. Java基础学习总结(78)——Java main方法深入研究学习

    1.不用main方法如何定义一个类? 不行,没有main方法我们不能运行Java类. 在Java 7之前,你可以通过使用静态初始化运行Java类.但是,从Java 7开始就行不通了. 2.main() ...

  3. 九度oj 题目1473:二进制数

    题目描述: 大家都知道,数据在计算机里中存储是以二进制的形式存储的. 有一天,小明学了C语言之后,他想知道一个类型为unsigned int 类型的数字,存储在计算机中的二进制串是什么样子的. 你能帮 ...

  4. 如何绘制caffe网络训练曲线

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51774966 当我们设计好网络结构后, ...

  5. HBase单节点的安装与配置

    HBase的安装配置1.下载:http://mirror.bit.edu.cn/apache/hbase/stable/   hbase-1.2.6-bin是直接编译好的,直接安装.   hbase- ...

  6. Ubuntu 16.04使用NASM编译时用ld链接程序出现:i386 架构于输入文件 sandbox.o 与 i386:x86-64 输出不兼容(I386 architecture in the input file sandbox.o is not compatible with i386: x86-64 output)

    错误: 问题解决过程: 1.先确定CPU的架构 2.这是以64位架构的CPU,如果使用elf参数时,默认是以32位模式去处理,那么此时需要更精确的去指定这个模式,比如elf32(32位),elf64( ...

  7. gh-ost: triggerless online schema migrations:Blog by Shlomi Noach:

    http://code.openark.org/blog/category/mysql https://rj03hou.github.io/mysql/gh-ost/

  8. ftk学习记(输入框篇)

    [ 声明:版权全部.欢迎转载.请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 昨天讲了进度条,我们还是看看它的运行效果是怎么样的.截图例如以下, 进度条使用的情况还是比較多的 ...

  9. Linux网络编程:UDP Socket编程范例

    TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯 ...

  10. C#程序猿学习 Python

    孙广东  2016.1.1 交互: C# 运行Python代码: http://stackoverflow.com/questions/11779143/run-a-python-script-fro ...