BZOJ_3545_[ONTAK2010]Peaks_主席树+倍增+kruscal重构树+dfs序
BZOJ_3545_[ONTAK2010]Peaks_主席树+倍增+kruscal重构树
Description
在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
Input
第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。
Output
对于每组询问,输出一个整数表示答案。
Sample Input
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
1 5 2
1 5 6
1 5 8
8 9 2
Sample Output
1
-1
8
HINT
【数据范围】
N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。
可以证明我们从一个点出发,走最小生成树上的边不会使经过的点变少。
于是需要想出一种方法能够快速找到所有长度小于等于x的边。
kruscal重构树建树方法:把边排序,对于一条边连接两个不同的连通块这种情况,我们新建一个结点。
两个连通块的父亲和其并查集的父亲指向新建的点,令边权为实际的边权。
这样我们得到了一棵结点数为2n-1的树。
这个树有一些性质:
1.每个叶子结点对应原树的结点,同时每个叶子结点向上找只会找到新建的结点。
2.对于原生成树的一个边权小于x的连通块,可以用kruscal重构树中的一个子树来表示。
根据这两个性质,我们处理每次询问,倍增一下找到边权小于x最高的位置。
然后相当于求一个子树第K大权值,用dfs序+主席树写一下即可。
需要注意的是,BZOJ最后一个点的图不连通。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 1000000001
inline char nc() {
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int rd() {
int x=0; char s=nc();
while(s<'0'||s>'9') s=nc();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
return x;
}
#define N 200050
#define M 500050
int head[N],to[N],nxt[N],val[N],fa[N],cnt,n,m,Q,h[N],f[22][N],dfn[N],son[N],tot,siz[N*20],ls[N*20],rs[N*20],se[N],root[N],H[N];
int find(int x) {
return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void add(int u,int v) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
struct E {
int a,b,c;
bool operator < (const E &x) const {
return c<x.c;
}
}e[M];
void insert(int l,int r,int v,int x,int &y) {
y=++tot; siz[y]=siz[x]+1;
if(l==r) return ;
int mid=(l+r)>>1;
if(v<=mid) rs[y]=rs[x],insert(l,mid,v,ls[x],ls[y]);
else ls[y]=ls[x],insert(mid+1,r,v,rs[x],rs[y]);
}
int qk(int l,int r,int k,int x,int y) {
if(l==r) return l;
int mid=(l+r)>>1;
int sizls=siz[ls[y]]-siz[ls[x]];
if(k<=sizls) return qk(l,mid,k,ls[x],ls[y]);
else return qk(mid+1,r,k-sizls,rs[x],rs[y]);
}
void dfs(int x) {
H[x]=1;
int i;
if(x<=n) se[x]=1,dfn[x]=++dfn[0],insert(-maxn,maxn,h[x],root[dfn[0]-1],root[dfn[0]]);
else dfn[x]=dfn[0]+1;
for(i=head[x];i;i=nxt[i]) {
f[0][to[i]]=x;
dfs(to[i]);
se[x]+=se[to[i]];
}
son[x]=dfn[0];
}
int main() {
n=rd(); m=rd(); Q=rd();
int i,j,x,v,k; tot=n;
for(i=1;i<=n;i++) h[i]=rd();
for(i=1;i<=m;i++) {
e[i].a=rd(); e[i].b=rd(); e[i].c=rd();
}
sort(e+1,e+m+1);
for(i=1;i<=2*n;i++) fa[i]=i;
for(i=1;i<=m;i++) {
int dx=find(e[i].a),dy=find(e[i].b);
if(dx==dy) continue;
tot++; fa[dx]=tot; fa[dy]=tot; add(tot,dx); add(tot,dy); val[tot]=e[i].c;
}
for(i=tot;i>=1;i--) if(!H[i]) dfs(i);
tot=0;
int ln=n<<1;
for(i=1;(1<<i)<ln;i++) {
for(j=1;j<ln;j++) {
f[i][j]=f[i-1][f[i-1][j]];
}
}
while(Q--) {
v=rd(); x=rd(); k=rd();
for(i=21;i>=0;i--) {
if(f[i][v]&&val[f[i][v]]<=x) v=f[i][v];
}
k=se[v]-k+1;
if(k<=0) puts("-1");
else printf("%d\n",qk(-maxn,maxn,k,root[dfn[v]-1],root[son[v]]));
}
}
BZOJ_3545_[ONTAK2010]Peaks_主席树+倍增+kruscal重构树+dfs序的更多相关文章
- 2018.09.30 bzoj3551:Peaks加强版(dfs序+主席树+倍增+kruskal重构树)
传送门 一道考察比较全面的题. 这道题又用到了熟悉的kruskal+倍增来查找询问区间的方法. 查到询问的子树之后就可以用dfs序+主席树统计答案了. 代码: #include<bits/std ...
- BZOJ 3551: [ONTAK2010]Peaks加强版 Kruskal重构树+dfs序+主席树+倍增
建出来 $Kruskal$ 重构树. 将询问点向上跳到深度最小,且合法的节点上. 那么,得益于重构树优美的性质,这个最终跳到的点为根的所有子节点都可以与询问点互达. 对于子树中求点权第 $k$ 大的问 ...
- BZOJ 3551: [ONTAK2010]Peaks加强版 [Kruskal重构树 dfs序 主席树]
3551: [ONTAK2010]Peaks加强版 题意:带权图,多组询问与一个点通过边权\(\le lim\)的边连通的点中点权k大值,强制在线 PoPoQQQ大爷题解传送门 说一下感受: 容易发现 ...
- bzoj 3551 kruskal重构树dfs序上的主席树
强制在线 kruskal重构树,每两点间的最大边权即为其lca的点权. 倍增找,dfs序对应区间搞主席树 #include<cstdio> #include<cstring> ...
- Luogu4899 IOI2018 Werewolf 主席树、Kruskal重构树
传送门 IOI强行交互可还行,我Luogu的代码要改很多才能交到UOJ去-- 发现问题是对边权做限制的连通块类问题,考虑\(Kruskal\)重构树进行解决. 对于图上的边\((u,v)(u<v ...
- BZOJ3551 ONTAK2010Peaks加强版(kruskal重构树+dfs序+主席树)
kruskal重构树本质就是给并查集显式建树来替代可持久化并查集.将边按困难度从小到大排序后建出该树,按dfs序建主席树即可.查询时跳到深度最浅的满足在该重要度下已被合并的点,在子树内查询第k大. # ...
- P4197 Peaks [克鲁斯卡尔重构树 + 主席树][克鲁斯卡尔重构树学习笔记]
Problem 在\(Bytemountains\)有\(n\)座山峰,每座山峰有他的高度\(h_i\) .有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个困难值,这个值越大表示越难走, ...
- 洛谷P3248 树 [HNOI2016] 主席树+倍增+分治
正解:主席树+倍增+分治 解题报告: 传送门! 首先看到这题会想到之前考过的这题 但是那题其实简单一些,,,因为那题只要用个分治+预处理就好,只是有点儿思维难度而已 这题就不一样,因为它说了是按照原树 ...
- kruscal重构树略解
我们先看一道题:Luogu P4197 Peaks 这道题珂以用启发式合并+主席树来做 那么强制在线呢?(bzoj 3551 [ONTAK2010]Peaks加强版) 离线做法就不行了 我们就要用一个 ...
随机推荐
- jquery怎么找到元素下面的第一个子元素
<ul><li>11</li><li>22</li><li>33</li><li>44</li&g ...
- SSH错误:packet_write_wait: Connection to 10.57.19.250 port 22: Broken pipe
现象:ssh连接以后,服务器会主动断开连接,wireshark抓包,发线服务器会tcp rst,断开ssh连接 解决尝试:1.修改会话超时时间:2.客户端主动间隔性向服务器发送保活报文:3.服务端主动 ...
- minimum-moves-to-equal-array-elements-ii(好)
https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/ package com.company; import ...
- PS 基础知识 .atn文件如何使用
ANT文件就是Frames.atn类动作文件 具体安装步骤如下 : (以CS4 为例) 启动Photoshop 点击"窗口" 选"动作" 在弹出的动作面板里,点 ...
- HEVC的參考队列解码
參考队列是指在进行帧间解码时.P或者B slice所參考的已解码的.位于解码图像缓存中(DPB, decoded picture buffer)中的图像队列,类似h264中的reflist0和refl ...
- java性能监控工具jcmd-windows
jcmd Sends diagnostic command requests to a running Java Virtual Machine (JVM). Synopsis jcmd [-l|-h ...
- 程序员必备字体Source Code Pro
最近捕获一枚,程序员专用字体,很不错. 介绍如下: Source Code Pro 是由大名鼎鼎的 Adobe 公司发布的一款开源免费的等宽编程字体,它非常适合用于显示代码,支持 Linux.Mac ...
- C语言-回溯例3
排列问题 1.实现排列A(n,m)对指定的正整数m,n(约定1<m<=n),具体实现排列A(n,m).2. 回溯算法设计设置一维数组a,a(i)(i=1,2,…,m)在1—n中取值.首先从 ...
- 由于扩展配置问题而无法提供您请求的页面...请添加 MIME 映射.--解决方法
http://blog.sina.com.cn/s/blog_4c78de680100quis.html HTTP 错误 404.3 - Not Found由于扩展配置问题而无法提供您请求的页面.如果 ...
- 深入Garbage First垃圾收集器(一)术语
Garbage垃圾收集器的原理,在这篇博客中有讲到,可以拿来参考下, Getting Started with the G1 Garbage Collector(译) 另外在这篇博客中也有讲到很多垃圾 ...