luogu3224 永无乡(动态开点,权值线段树合并)
luogu3224 永无乡(动态开点,权值线段树合并)
永无乡包含 n 座岛,编号从 1 到 n ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以 到达岛 b ,则称岛 a 和岛 b 是连通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x 连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪座,请你输出那个岛的编号。n≤100000,m≤n,q≤300000。
首先,对于每个岛建一个权值线段树,然后根据初始边将它们合并。对于在同一个联通块里的点,通过并查集选出其中一个点x,root[x]代表这个联通块的线段树的根。对于查询,第k重要的岛可以通过在权值线段树里的二分来确定。合并时,规定将x合并到y。
为什么时间复杂度是nlogn呢?
考虑点数的变化。刚开始的时候有nlogn个结点,最后只有2n个结点。因此,消失的结点数目是nlogn级别的。由于对两个结点的一次合并,消耗了一个结点,同时花费\(O(1)\),所以总的时间复杂度是\(O(nlogn)\)。
#include <cctype>
#include <cstdio>
using namespace std;
const int maxn=1e5+5, maxseg=maxn*20;
//v:表示一个岛的重要性 id:重要性反推是哪个结点 fa:用来找到与线段树对应的结点
int n, m, q, v[maxn], id[maxn], fa[maxn];
//root:将岛的编号映射在线段树根位置上 lc,rc:线段树结点的左右孩子
int cnt, root[maxn], lc[maxseg], rc[maxseg], seg[maxseg];
void get(int &x){
int flag=1; char c;
for (c=getchar(); !isdigit(c); c=getchar())
if (c=='-') flag=-1;
for (x=c-48; c=getchar(), isdigit(c); )
x=(x<<3)+(x<<1)+c-48; x*=flag;
}
int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); }
//给权值线段树增加一个值
void add(int &x, int l, int r, int pos){
if (!x) x=cnt++;
if (l==r){ ++seg[x]; return; }
int mid=(l+r)>>1;
if (pos>mid) add(rc[x], mid+1, r, pos);
else add(lc[x], l, mid, pos);
seg[x]=seg[lc[x]]+seg[rc[x]];
}
//将x归并到y上,并返回y(nlogn)
//普通的merge不能这样写!(两个孩子都是空结点)
int merge(int x, int y){
//返回存在的子节点。如果子节点都不存在,返回的是空结点
if (!x) return y; if (!y) return x;
lc[y]=merge(lc[x], lc[y]);
rc[y]=merge(rc[x], rc[y]);
seg[y]=seg[lc[y]]+seg[rc[y]];
return y;
}
//在权值线段树中找到第k个点(logn)
int query(int now, int l, int r, int k){
if (l==r) return l;
int mid=(l+r)>>1;
if (seg[lc[now]]>=k) return query(lc[now], l, mid, k);
else return query(rc[now], mid+1, r, k-seg[lc[now]]);
}
int main(){
get(n); get(m);
for (int i=1; i<=n; ++i){
get(v[i]); id[v[i]]=i;
fa[i]=i; root[i]=cnt++;
add(root[i], 1, n, v[i]);
}
int t1, t2;
for (int i=0; i<m; ++i){
get(t1); get(t2);
merge(root[find(t1)], root[find(t2)]);
fa[find(t1)]=find(t2);
}
get(q); char c; int x, y;
for (int i=0; i<q; ++i){
while (!isgraph(c=getchar()));
get(x); get(y);
if (c=='Q'){
x=root[find(x)];
if (seg[x]<y) puts("-1");
else printf("%d\n", id[query(x, 1, n, y)]);
} else {
merge(root[find(x)], root[find(y)]);
fa[find(x)]=find(y);
}
}
return 0;
}
luogu3224 永无乡(动态开点,权值线段树合并)的更多相关文章
- 【HNOI2012】永无乡 题解(并查集+线段树合并)
题目链接 给定一张含$n$个点$m$条边的无向图,每个点有一个重要指数$a_i$.有两种操作:1.在$x$和$y$之间连一条边:2.求$x$所在连通块中重要程度第$k$小的点. ----------- ...
- P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)
题意:带修求区间k小 题解:回忆在使用主席树求区间k小时 利用前缀和的思想 既然是前缀和 那么我们可以使用更擅长维护前缀和的树状数组 但是这里每一颗权值线段树就不是带版本的 而是维护数组里i号点的权值 ...
- HDU 6464.免费送气球-动态开点-权值线段树(序列中第first小至第second小的数值之和)(感觉就是只有一个状态的主席树) (“字节跳动-文远知行杯”广东工业大学第十四届程序设计竞赛)
免费送气球 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submi ...
- B20J_2733_[HNOI2012]永无乡_权值线段树合并
B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...
- 【bzoj4399】魔法少女LJJ 并查集+权值线段树合并
题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味: ...
- HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)
layout: post title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并) author: "luowentaoaa&quo ...
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...
- 【bzoj4719】[Noip2016]天天爱跑步 权值线段树合并
题目描述 给出一棵n个点的树,以及m次操作,每次操作从起点向终点以每秒一条边的速度移动(初始时刻为0),最后对于每个点询问有多少次操作在经过该点的时刻为某值. 输入 第一行有两个整数N和M .其中N代 ...
- 【bzoj2212】[Poi2011]Tree Rotations 权值线段树合并
原文地址:http://www.cnblogs.com/GXZlegend/p/6826614.html 题目描述 Byteasar the gardener is growing a rare tr ...
随机推荐
- Python基础之元组操作
元组的常用操作包括但不限于以下操作: 元组的索引,计数等 这里将对列表的内置操作方法进行总结归纳,重点是以示例的方式进行展示. 使用type获取创建对象的类 type(tuple) 使用dir获取类的 ...
- 2018-06-07 RF test 1 :TX Power test
Test item: 1.Output power: 屏蔽网房-同轴线-频谱仪 The radio circuitry, generally referred to as the Device U ...
- C语言小程序(四)、杨辉三角
输入要显示的杨辉三角的行数,会打印出金字塔型的杨辉三角,不过行数太多的话,效果不太好,可以再调整一下格式控制. #include <stdio.h> #include <stdlib ...
- OpenCV - Windows(win10)编译opencv + opencv_contrib
在之前的几篇文章中,我提到了在Android.Linux中编译opencv + opencv_contrib,这篇文章主要讲在Windows中编译opencv + opencv_contrib. 首先 ...
- 本机不装Oracle,使用plsql连接远程Oracle的方法
由于Oracle的庞大,有时候我们需要在只安装Oracle客户端如plsql.toad等的情况下去连接远程数据库,可是没有安装Oracle就没有一切的配置文件去支持.最后终于发现一个很有效的方法,Or ...
- Unity3D中的Coroutine及其使用(延时、定时调用函数)
http://blog.csdn.net/nizihabi/article/details/47606887 一.Coroutine(协程)的概念和本质 在网上的一些资料当中,一直将Coroutine ...
- python mysql 查询返回字典结构
cur = self.conn.cursor(MySQLdb.cursors.DictCursor)加上MySQLdb.cursors.DictCursor可以返回字典结构 {列名:值} class ...
- Trie(前缀树/字典树)及其应用
Trie,又经常叫前缀树,字典树等等.它有很多变种,如后缀树,Radix Tree/Trie,PATRICIA tree,以及bitwise版本的crit-bit tree.当然很多名字的意义其实有交 ...
- 都是stm32的JTAG引脚惹的祸
转载请注明出处:http://blog.csdn.net/qq_26093511/article/category/6094215 最近在调试08接口的LED显示屏,使用的是自己做的STM32板子. ...
- linux strace-跟踪进程的系统调用或是信号产生情况,lstrace-跟踪己丑年调用库函数情况,进程跟踪调试命令
本工具可以用来做大多数排除,比如mount一个NFS,很慢,找不出原因,我们可以使用strace命令来跟中mount这个经常所有的调用过程. strace 命令是一种强大的工具,它能够显示所有由用户空 ...