Peaks 线段树合并

\(n\)个带权值\(h_i\)山峰,有\(m\)条山峰间双向道路,\(q\)组询问,问从\(v_i\)开始只经过\(h_i\le x\)的路径所能到达的山峰中第\(k\)高的山峰,如果无解输出\(-1\)

线段树合并好题。吊打主席树、Kruskal重构树的典范

首先发现可以离线,我们将所有询问按\(x\)排序,随着询问再去加边,这样可以去掉路径上\(h_i\le x\)这一条件使问题极大简化。

然后从\(v_i\)开始能经过的所有山峰可以看做联通块,于是我们愉快地用并查集维护,用权值线段树查询第\(k\)大,合并联通块时合并权值线段树即可。很像[HNOI2012]永无乡

另外注意此题是查询第\(k\)大,不是第\(k\)小。

#include <cstdio>
#include <algorithm>
#define MAXN 100010
#define MAXM 500005
using namespace std;
int n,m,q;
inline int read(){
char ch=getchar();int s=0;
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') s=s*10+ch-'0', ch=getchar();
return s;
}
int h[MAXN],h_sort[MAXN],rnk[MAXN];
struct nod{
int u,v,val;
} edge[MAXM];
bool cmp_nod(const nod &a, const nod &b){
return a.val<b.val;
}
struct question{
int v,x,k;
int id;
} qs[MAXM];
bool cmp_qs(const question &a, const question &b){
return a.x<b.x;
}
int res[MAXM];
int fa[MAXN];
int get_fa(int x){
if(fa[x]==x) return x;
return fa[x]=get_fa(fa[x]);
}
#define MAXT MAXN*20
int rot[MAXN],tot,s;
int tre[MAXT],sl[MAXT],sr[MAXT];
void change(int &x, int l, int r, int pos){
if(x==0) x=++tot;
tre[x]+=1;
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) change(sl[x], l, mid, pos);
else change(sr[x], mid+1, r, pos);
}
int query(int x, int l, int r, int k){
if(x==0||tre[x]<k) return 0; // 如果不存在则返回0
if(l==r) return l;
int mid=(l+r)>>1;
if(tre[sr[x]]>=k) return query(sr[x], mid+1, r, k); // 找第k大所以先找右儿子
else return query(sl[x], l, mid, k-tre[sr[x]]);
}
int merge(int a, int b, int l, int r){
if(a==0||b==0) return a+b;
if(l==r){
tre[a]+=tre[b];
return a;
}
int mid=(l+r)>>1;
sl[a]=merge(sl[a], sl[b], l, mid);
sr[a]=merge(sr[a], sr[b], mid+1, r);
tre[a]=tre[sl[a]]+tre[sr[a]]; // 记得合并后更新
return a;
}
void merge_edge(int x){
int fa1=get_fa(edge[x].u),fa2=get_fa(edge[x].v);
if(fa1==fa2) return; // 如果已经都联通了则不需要合并线段树了
fa[fa2]=fa1;
rot[fa1]=merge(rot[fa1], rot[fa2], 1, s);
}
int main(){
n=read(),m=read(),q=read();
for(int i=1;i<=n;++i) fa[i]=i;
for(int i=1;i<=n;++i) h_sort[i]=h[i]=read();
sort(h_sort+1, h_sort+1+n);
s=unique(h_sort+1, h_sort+1+n)-(h_sort+1);
for(int i=1;i<=n;++i){
rnk[i]=lower_bound(h_sort+1, h_sort+1+s, h[i])-h_sort; // 离散化
change(rot[i], 1, s, rnk[i]);
}
for(int i=1;i<=m;++i) edge[i].u=read(),edge[i].v=read(),edge[i].val=read();
sort(edge+1, edge+1+m, cmp_nod);
for(int i=1;i<=q;++i) qs[i].v=read(),qs[i].x=read(),qs[i].k=read(),qs[i].id=i;
sort(qs+1, qs+1+q, cmp_qs);
int pos=1;
for(int i=1;i<=q;++i){
int x=qs[i].x,v=qs[i].v,k=qs[i].k;
while(pos<=m&&edge[pos].val<=x) merge_edge(pos),++pos; // 把小于等于x的边加入
int ans=query(rot[get_fa(v)], 1, s, k);
if(ans==0) res[qs[i].id]=-1;
else res[qs[i].id]=h_sort[ans]; // 最后答案不是下标而是对应的值
}
for(int i=1;i<=q;++i) printf("%d\n", res[i]);
return 0;
}

Peaks 线段树合并的更多相关文章

  1. 【bzoj3545】[ONTAK2010]Peaks 线段树合并

    [bzoj3545][ONTAK2010]Peaks 2014年8月26日3,1512 Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路 ...

  2. BZOJ.3545.[ONTAK2010]Peaks(线段树合并)

    题目链接 \(Description\) 有n个座山,其高度为hi.有m条带权双向边连接某些山.多次询问,每次询问从v出发 只经过边权<=x的边 所能到达的山中,第K高的是多少. \(Solut ...

  3. bzoj3545 Peaks 线段树合并

    离线乱搞... 也就是一个线段树合并没什么 #include<algorithm> #include<iostream> #include<cstring> #in ...

  4. 【线段树合并】bzoj3545: [ONTAK2010]Peaks

    1A还行 Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问, ...

  5. [BZOJ3545] [ONTAK2010]Peaks(线段树合并 + 离散化)

    传送门 由于困难值小于等于x这个很恶心,可以离线处理,将边权,和询问时的x排序. 每到一个询问的时候,将边权小于等于x的都合并起来再询问. .. 有重复元素的线段树合并的时间复杂度是nlog^2n # ...

  6. BZOJ3545 Peaks 离线处理+线段树合并

    题意: 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经 ...

  7. 线段树合并&&启发式合并笔记

    这俩东西听起来很高端,实际上很好写,应用也很多~ 线段树合并 线段树合并,顾名思义,就是建立一棵新的线段树保存原有的两颗线段树的信息. 考虑如何合并,对于一个结点,如果两颗线段树都有此位置的结点,则直 ...

  8. [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】

    题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动 ...

  9. [BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】

    题目链接:BZOJ - 2212 题目分析 子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对. 左右子树内部的逆序对与是否交换 ...

随机推荐

  1. Jmeter之分布式测试/压测

    Jmeter做分布式测试的原因: 测试机器的配置低,对服务器进行压测时,造成不了压力. jmeter并发10000后,测试机就已经卡顿了,而且测试结果有大量失败(忽略了jmeter自身问题=.=||| ...

  2. 邮件标准协议:MIME(Multipurpose Internet Mail Extensions)

    MIME(多用途互联网邮件扩展)指的是一系列电子邮件技术规范 ,主要包括 RFC 2045~2049   传统的电子邮件只能使用 ASCII 字符,导致非英文字符都不能在电子邮件中使用 而且电子邮件中 ...

  3. flutter从入门到精通五

    在flutter的世界里,一切都是Widget,图像,文本,布局模型等等,一切都是Widget flutter中,尽量将Widget放在MaterialApp.其封装了所需要的一些Widget,Mat ...

  4. Python之数据处理-2

    一.数据处理其实是一个很麻烦的事情. 在一个样本中存在特征数据(比如:人(身高.体重.出生年月.年龄.职业.收入...))当数据的特征太多或者特征权重小或者特征部分满足的时候. 这个时候就要进行数据的 ...

  5. dll库生成和使用

    抄自http://www.cnblogs.com/fangyukuan/archive/2010/06/20/1761464.html 1. VS2010中新建Win32-Win32项目,输入名称Dl ...

  6. kvm第五章--虚拟迁移

  7. 【转】使用Scanner输入字符串时next()和nextLine()区别

    在实现字符窗口的输入时,很多人更喜欢选择使用扫描器Scanner,它操作起来比较简单.在编程的过程中,我发现用Scanner实现字符串的输入有两种方法,一种是next(),一种nextLine(),但 ...

  8. JavaScript CryptoJS库 加密与解密

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 开源项目hutool之zip_slip漏洞

    今天突然看到了去年写的一篇漏洞分析文章,搬到博客上 ---------------- Hutool是Github上的一个开源项目,是一个java的工具包,对文件.流.加密解密.转码.正则.线程.XML ...

  10. Dubbo面试

    DUBBO原理.应用与面经总结 SPI 你是否了解SPI,讲一讲什么是SPI,为什么要使用SPI? SPI具体约定:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/serv ...