【题解】永无乡 [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. buf.readUInt32BE()函数详解

    buf.readUInt32BE(offset[, noAssert]) buf.readUInt32LE(offset[, noAssert]) offset {Number} 0 noAssert ...

  2. Python json & pickle & shelve模块

    json & pickle 之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇 ...

  3. 如何相互转换逗号分隔的字符串和List --https://blog.csdn.net/yywusuoweile/article/details/50315377

    如何相互转换逗号分隔的字符串和List ---https://blog.csdn.net/yywusuoweile/article/details/50315377 方法 2: 利用Guava的Joi ...

  4. 【BZOJ2434】阿狸的打字机(fail树,DFS序)

    题意: 1<=N<=10^5 1<=M<=10^5 输入总长<=10^5   思路: From http://blog.csdn.net/lych_cys/article ...

  5. Tomcat配置文件server.xml(转)

    前言 Tomcat隶属于Apache基金会,是开源的轻量级Web应用服务器,使用非常广泛.server.xml是Tomcat中最重要的配置文件,server.xml的每一个元素都对应了Tomcat中的 ...

  6. Java中DAO/DTO/PO/VO/BO/QO/POJO

    ORM:是Object Relational Mapping(对象关系映射)的缩写. 通俗点讲,就是将对象与关系数据库绑定,用对象来表示关系数据.在O/R/M的世界里,有两个基本的也是重要的东东需要了 ...

  7. springboot启动mybatis

    初期开发了generator可以根据表结果自动生产实体类.配置文件和dao层代码,可以减轻一部分开发量:后期也进行了大量的优化可以使用注解了,自动管理dao层和配置文件等,发展到最顶端就是今天要讲的这 ...

  8. mac下,redis的安装与配置

    一.安装redis 1.到官网下载redis最新版本号,我下载的是3.0.3 http://redis.io/ 2.拷贝redis-3.0.3到/usr/local文件夹 3.解压缩sudo tar ...

  9. iOS屏幕适配方案-Auto Layout

    市场上的android手机五花八门.各种尺寸的屏幕让android程序员们比較头疼. 也有一些大神写了一些博客提出了自己的观点.iOS貌似也迎来了大屏6+,因此屏幕适配的问题也是有滴,因此苹果也有自己 ...

  10. 百度开放云java+tomcat部署web项目-小皇帝詹姆斯

    加入部署 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/diss ...