洛谷 P3224 [HNOI2012]永无乡 解题报告
P3224 [HNOI2012]永无乡
题目描述
永无乡包含 \(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\) 或 \(B\) 开始,后面跟两个不超过 \(n\) 的正整数,字母与数字以及两个数字之间用空格隔开。
输出格式:
对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出 \(−1\) 。
说明
对于 \(20\%\) 的数据 \(n \leq 1000, q \leq 1000\)
对于 \(100\%\) 的数据 \(n \leq 100000, m \leq n, q \leq 300000\)
题意:点有点权,维护连通块的第\(k\)值,支持加边操作
维护第\(k\)值可以使用主席树平衡树等,这里我使用主席树
加边额外并查集维护,合并直接启发式合并,查询直接查询即可
复杂度分析
设所有的块都被合并到一块去了,且每次合并两个块时它们的大小相等
则有式子
\(T(n)=2\times T(\frac{n}{2})+\frac{n}{2}log\frac{n}{2}\)
合并的复杂度是那个是因为一个有\(s\)大小的块的主席树的链的条数有\(s\)条
updata:又玩了玩复杂度,发现似乎最坏复杂度是这样,但不能这么简单的说明,我自己也不太清楚,当做大约是\(n\)个节点的合并的复杂度在\(O(n)-O(nlogm)\)左右的吧,如果有什么能说清楚复杂度的,烦请跟我说一声QAQ
总复杂度:\(O(nlog^2n)\)
Code:
#include <cstdio>
#include <algorithm>
const int N=1e5+10;
int a[N],b[N],num[N];
int root[N],ch[N*20][2],sum[N*20],tot,f[N],siz[N],n,m,q;
#define ls ch[now][0]
#define rs ch[now][1]
void updata(int now){sum[now]=sum[ls]+sum[rs];}
int build(int l,int r,int pos)
{
int now=++tot;
if(l==r)
{
sum[now]=1;
return now;
}
int mid=l+r>>1;
if(pos<=mid) ls=build(l,mid,pos);
else rs=build(mid+1,r,pos);
updata(now);
return now;
}
int Find(int x){return f[x]==x?x:Find(f[x]);}
#define ols ch[las][0]
#define ors ch[las][1]
void merge(int &now,int las,int l,int r)
{
if(!now) {now=las;return;}
if(l==r)
{
sum[now]+=sum[las];
return;
}
int mid=l+r>>1;
if(ols) merge(ls,ols,l,mid);
if(ors) merge(rs,ors,mid+1,r);
updata(now);
}
void swap(int &x,int &y){x+=y,y=-y,y+=x,x-=y;}
void Merge(int x,int y)
{
x=Find(x),y=Find(y);
if(x==y) return;
if(siz[x]<siz[y]) swap(x,y);
merge(root[x],root[y],1,n);
siz[x]+=siz[y];
f[y]=x;
}
int query(int now,int l,int r,int k)
{
if(sum[now]<k) return -1;
if(l==r) return num[l];
int mid=l+r>>1;
if(sum[ls]>=k) return query(ls,l,mid,k);
else return query(rs,mid+1,r,k-sum[ls]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",a+i),b[i]=a[i];
std::sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
b[i]=std::lower_bound(a+1,a+1+n,b[i])-a;
for(int i=1;i<=n;i++)
num[b[i]]=i,f[i]=i,siz[i]=1,root[i]=build(1,n,b[i]);
for(int u,v,i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
Merge(u,v);
}
scanf("%d",&q);
char op[5];
for(int u,v,i=1;i<=q;i++)
{
scanf("%s%d%d",op,&u,&v);
if(op[0]=='B') Merge(u,v);
else printf("%d\n",query(root[Find(u)],1,n,v));
}
return 0;
}
2018.9.3
洛谷 P3224 [HNOI2012]永无乡 解题报告的更多相关文章
- 洛谷P3224 [HNOI2012]永无乡(线段树合并+并查集)
题目描述 永无乡包含 nnn 座岛,编号从 111 到 nnn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nnn 座岛排名,名次用 111 到 nnn 来表示.某些岛之间由巨大的桥连接, ...
- 洛谷 P3224 [HNOI2012]永无乡
题面 永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 \(1\) 到 \(n\) 来表示.某些岛 ...
- [洛谷P3224][HNOI2012]永无乡
题目大意:给你$n$个点,每个点有权值$k$,现有两种操作: 1. $B\;x\;y:$将$x,y$所在联通块合并2. $Q\;x\;k:$查询第$x$个点所在联通块权值第$k$小是哪个数 题解:线段 ...
- 2018.08.11 洛谷P3224 [HNOI2012]永无乡(线段树合并)
传送门 给出n个带点权的点,支持连边和查询连通块第k大. 这个貌似就是一道线段树合并的裸板啊... 代码: #include<bits/stdc++.h> #define N 100005 ...
- [HNOI2012] 永无乡 解题报告 (splay+启发式合并)
题目链接:https://www.luogu.org/problemnew/show/P3224#sub 题目: 题目大意: 维护多个联通块,没有删除操作,每次询问某一联通块的第k大 解法: 维护联通 ...
- 【洛谷P3224】永无乡 并查集+Splay启发式合并
题目大意:给定 N 个点的图,点有点权,初始有一些无向边,现在有 Q 个询问,每个询问支持动态增加一条无向边连接两个不连通的点和查询第 X 个点所在的联通块中权值第 K 大的是哪个点. 题解:学会了平 ...
- 洛谷.3224.[HNOI2012]永无乡(Splay启发式合并)
题目链接 查找排名为k的数用平衡树 合并时用启发式合并,把size小的树上的所有节点插入到size大的树中,每个节点最多需要O(logn)时间 并查集维护连通关系即可 O(nlogn*insert t ...
- 线段树合并+并查集 || BZOJ 2733: [HNOI2012]永无乡 || Luogu P3224 [HNOI2012]永无乡
题面:P3224 [HNOI2012]永无乡 题解: 随便写写 代码: #include<cstdio> #include<cstring> #include<iostr ...
- P3224 [HNOI2012]永无乡 题解
P3224 [HNOI2012]永无乡 题解 题意概括 有若干集合,每个集合最初包含一个值,和一个编号1~n.两个操作:合并两个集合,查询包含值x的集合中第k大值最初的集合编号. 思路 维护集合之间关 ...
随机推荐
- 没有CTO的Netflix有哪些值得我们学习的工程文化?
作者介绍: 杨波,拍拍贷基础框架研发总监.具有超过 10 年的互联网分布式系统研发和架构经验,曾先后就职于:eBay 中国研发中心(eBay CDC),任资深研发工程师,参与亿贝开放 API 平台研发 ...
- springmvc 前端表单提交给后端出现乱码
在springmvc框架练习中遇到了乱码问题,经过一番网上查找解决方法之后,最后发现是需要在tomcat中的server.xml中添加编码设置 URIEncoding="UTF-8" ...
- JS - CommonJS、AMD、CMD
CommonJS CommonJS是一种JS模块定义规范,它出现之初是为了解决JS天生没有模块管理的缺陷,它的终极目标是提供一个类似Python.Ruby和Java标准库.NodeJS的模块系统就是参 ...
- input宽度超出
设置样式:style=“width:100%”;即可
- Linux下Mysql5.6 二进制安装
1.1下载二进制安装包 wget https://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.40-linux-glibc2.12-x86_64.t ...
- LEA指令与MOV指令区别
Tips: LEA指令与MOV指令的区别: ① MOV指令是 数据 传送指令-------传送数据 LEA指令是 有效地址 传送指令-------取偏移地址 ② MOV OPRD1 ...
- #Python编程从入门到实践#第三章笔记
列表简介 1.什么是列表 列表:由一系列按也顶顺序排列的元素组成.元素之间可以没有任何关系. 列表:用方括号[]表示,并用逗号分隔其中元素.名称一般为复数 2.访问元素 (1)列表是有序集合 ...
- 笔记-docker-3 使用
笔记-docker-3 使用 1. 镜像 image是docker最重要的概念,docker运行容器前需要本地存在对应的镜像,如果没有,会尝试从默认镜像库下载. 1.1. 镜像获取 查 ...
- 20145202马超 《Java程序设计》第三周学习总结
************************http://git.oschina.net/tuolemi/java这是git的那个网址********************* 函数的重载:在同一 ...
- CSAcademy Palindromic Concatenation 字符串哈希
题意: 题目链接 给出\(n\)个字符串,求有多少对\((i,j),i \neq j\)使得\(s_i\)与\(s_j\)拼起来是回文串 分析: 设\(s_i,s_j\)的长度分别为\(L_i, L_ ...