【题解】永无乡 [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. 微信小程序,获取点击元素的索引值index

    1.需求说明 点击 “加号图片” 上传图片,需要知道点击的是第几个图片,动态的修改src数组,这里图片用的 wx:for 循环出来的 2.遇到问题 按照官方最新文档循环的方式,索引值是以  wx:fo ...

  2. 深度完整的了解MySQL锁

    今天就讲讲MySQL的锁 主讲:Mysql的悲观锁 和 乐观锁官方:If you query data and then insert or update related data within th ...

  3. CodeForces 800B Volatile Kite(点与直线的距离)(Java 实现)

    CodeForces 800B Volatile Kite(点与直线的距离)(Java 实现) 传送门 如果想要一个凸多边形不退化为凹多边形,那么任意的相邻的三个点必然最多形成一条直线.因此我们可以求 ...

  4. FJoi2017 1月20日模拟赛 直线斯坦纳树(暴力+最小生成树+骗分+人工构造+随机乱搞)

    [题目描述] 给定二维平面上n个整点,求该图的一个直线斯坦纳树,使得树的边长度总和尽量小. 直线斯坦纳树:使所有给定的点连通的树,所有边必须平行于坐标轴,允许在给定点外增加额外的中间节点. 如下图所示 ...

  5. HTML5中Canvas概述

    一.HTML5 Canvas历史 Canvas的概念最初是由苹果公司提出的,用于在Mac OS X WebKit中创建控制板部件(dashboard widget).在Canvas出现之前,开发人员若 ...

  6. IDEA下tomcat中web项目乱码,控制台乱码解决指南

    若是由于过滤器,request ,response等原因,不适用. 原文作者:http://www.kafeitu.me/tools/2013/03/26/intellij-deal-chinese- ...

  7. Navigator的学习

      Navigator 对象包含有关浏览器的信息.注释:没有应用于 navigator 对象的公开标准,不过所有浏览器都支持该对象.   我感觉需要看什么属性和方法,直接输出这个navigator,然 ...

  8. Java 学习(6):java Number & Math & String & 数组...常用类型

    目录 --- Number & Math类 --- Character 类 --- String 类 --- StringBuffer 类 --- 数组 Number & Math类: ...

  9. [bzoj4033][HAOI2015]树上染色_树形dp

    树上染色 bzoj-4033 HAOI-2015 题目大意:给定一棵n个点的树,让你在其中选出k个作为黑点,其余的是白点,收益为任意两个同色点之间距离的和.求最大收益. 注释:$1\le n\le 2 ...

  10. P1009 阶乘之和 洛谷

    https://www.luogu.org/problem/show?pid=1009 题目描述 用高精度计算出S=1!+2!+3!+…+n!(n≤50) 其中“!”表示阶乘,例如:5!=54321. ...