P4197 Peaks
题目描述
在Bytemountains有N座山峰,每座山峰有他的高度\(h_i\)。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
输入输出格式
输入格式:
第一行三个数N,M,Q。 第二行N个数,第ii个数为\(h_i\) 接下来MM行,每行33个数a,b,c,表示从a到b有一条困难值为c的双向路径。 接下来Q行,每行三个数v,x,k,表示一组询问。
输出格式:
对于每组询问,输出一个整数表示答案。
输入输出样例
输入样例#1: 复制
10 11 4
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
输出样例#1: 复制
6
1
-1
8
说明
数据范围
\(N \le 10^5, 0 \le M,Q \le 5\times 10^5,h_i,c,x \le 10^9\)。
kruskal重构树
对于每一个节点其子树的叶子就是在这个点的权值内能相互到达的点
按照dfs序建可持久化权值线段树,dfs序\(u\)到\(u+size[u]\)内每个点的增量就是\(pre[u]\)子树的点
每次查询时把\(v\)倍增跳到\(\leq x\)的最大值,在\((dfn[x]+size[x])-(dfn[x]-1)\)的线段树内找第\(k\)大节点即可
恩......
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define M (200005*10)
#define N 200005
#define LL long long
#define max(a,b) ((a)>(b)? (a):(b))
#define min(a,b) ((a)<(b)? (a):(b))
using namespace std;
int top[N],d[M],h[N],ls[M],rs[M],n,m,q,cnt,f[N],edge[N],cnt1,y;
int head[N],ver[N],nex[N],dfn[N],df,pre[M],g,z[N],pp[N],v,x,k,bz[N][26],s[N],az[N][26];
struct vv{ int f,t,edge;} a[M];
inline bool cmp(vv a,vv b) {return a.edge<b.edge;}
inline char gc()
{
static char now[1<<22],*S,*T;
if (T==S)
{
T=(S=now)+fread(now,1,1<<22,stdin);
if (T==S) return EOF;
}
return *S++;
}
inline int gtt()
{
register int x=0,f=1;
register char ch=gc();
while(!isdigit(ch))
{
if (ch=='-') f=-1;
ch=gc();
}
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=gc();
return x*f;
}
inline void add(int x,int y)
{
cnt1+=1;
ver[cnt1]=y; nex[cnt1]=head[x]; head[x]=cnt1;
}
int ff(int x)
{
if(f[x]==x) return x;
f[x]=ff(f[x]);
return f[x];
}
inline void kru()
{
for(int i=1;i<=m;i++)
{
int w=ff(a[i].f), e=ff(a[i].t);
if(w!=e)
{
f[w]=f[e]=++n;
add(n,w); add(n,e);
edge[n]=a[i].edge;
}
}
}
void dfs(int now)
{
bz[now][0]=edge[now];
s[now]=1; dfn[now]=++df; pre[df]=now;
for(int i=head[now];i;i=nex[i])
{
int t=ver[i];
dfs(t);
bz[t][1]=edge[now];
az[t][1]=now;
s[now]+=s[t];
}
}
void built(int now,int l,int r,int pre,int z)
{
if(l==r)
{
d[now]=d[pre]+1;
return;
}
int mid=(l+r)>>1; ls[now]=ls[pre]; rs[now]=rs[pre];
if(z<=mid)
{
ls[now]=++cnt;
built(ls[now],l,mid,ls[pre],z);
}
if(z>mid)
{
rs[now]=++cnt;
built(rs[now], mid+1, r, rs[pre], z);
}
d[now]=d[ls[now]]+d[rs[now]];
}
void built1(int now,int l,int r)
{
if(l==r) return;
ls[now]=++cnt; rs[now]=++cnt;
int mid=(l+r)>>1;
built1(ls[now], l, mid);
built1(rs[now], mid+1, r);
}
int find(int now1,int now2,int l,int r,int z)
{
if(l==r) return l;
if(d[now2]-d[now1]<z) return -1;
int mid=(l+r)>>1;
if(d[rs[now2]]-d[rs[now1]]>=z) return find(rs[now1], rs[now2], mid+1, r, z);
return find(ls[now1], ls[now2], l, mid, z-d[rs[now2]]+d[rs[now1]]);
}
int main()
{
n=gtt(); m=gtt(); q=gtt(); g=n;
for(int i=1;i<=4*n;i++) f[i]=i;
for(int i=1;i<=n;i++) h[i]=gtt(), z[i]=h[i];
sort(z+1,z+1+n);
int mm=unique(z+1,z+1+n)-z-1;
for(int i=1;i<=n;i++)
{
k=lower_bound(z+1,z+1+mm,h[i])-z;
pp[k]=h[i]; h[i]=k;
}
for(int i=1;i<=m;i++){ a[i].f=gtt(); a[i].t=gtt(); a[i].edge=gtt();}
sort(a+1,a+1+m,cmp); kru();
for(int i=n;i;i--) if(!dfn[i]) dfs(i);
if(g!=1){top[1]=1; cnt=1; built1(1,1,mm);}
else {top[1]=1; cnt=1;built(cnt,1,mm,0,h[pre[1]]);}
for(int i=2;i<=n;i++)
if(pre[i]<=g)
{
top[i]=++cnt;
built(cnt,1,mm,top[i-1],h[pre[i]]);
}
else top[i]=top[i-1];
for(int i=2;i<=25;i++)
for(int j=1;j<=n;j++)
bz[j][i]=bz[az[j][i-1]][i-1], az[j][i]=az[az[j][i-1]][i-1];
for(int i=1;i<=q;i++)
{
v=gtt(); x=gtt(); k=gtt();
for(int j=25;j>=1;j--) if(bz[v][j]<=x && az[v][j]) v=az[v][j];
k=find(top[dfn[v]-1],top[dfn[v]+s[v]-1],1,mm,k);
if(k!=-1)printf("%d\n",pp[k]);
else printf("-1\n");
}
}
P4197 Peaks的更多相关文章
- BZOJ 3545 / 洛谷 P4197 Peaks 解题报告
P4197 Peaks 题目描述 在\(\text{Bytemountains}\)有\(N\)座山峰,每座山峰有他的高度\(h_i\).有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个 ...
- [luogu P4197] Peaks 解题报告(在线:kruskal重构树+主席树 离线:主席树+线段树合并)
题目链接: https://www.luogu.org/problemnew/show/P4197 题目: 在Bytemountains有N座山峰,每座山峰有他的高度$h_i$.有些山峰之间有双向道路 ...
- Luogu P4197 Peaks
题目链接 \(Click\) \(Here\) 做法:\(Kruskal\)重构树上跑主席树 构造方法:把每条边拆出来成一个点,点权是原先的边权.每次连边的时候,连的不再是点,而是其原先点所在的联通块 ...
- 洛谷P4197 Peaks&&克鲁斯卡尔重构树学习笔记(克鲁斯卡尔重构树+主席树)
传送门 据说离线做法是主席树上树+启发式合并(然而我并不会) 据说bzoj上有强制在线版本只能用克鲁斯卡尔重构树,那就好好讲一下好了 这里先感谢LadyLex大佬的博客->这里 克鲁斯卡尔重构树 ...
- 洛谷P4197 Peaks(Kruskal重构树 主席树)
题意 题目链接 往后中文题就不翻译了qwq Sol 又是码农题..出题人这是强行把Kruskal重构树和主席树拼一块了啊.. 首先由于给出的限制条件是<=x,因此我们在最小生成树上走一定是最优的 ...
- P4197 Peaks [克鲁斯卡尔重构树 + 主席树][克鲁斯卡尔重构树学习笔记]
Problem 在\(Bytemountains\)有\(n\)座山峰,每座山峰有他的高度\(h_i\) .有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个困难值,这个值越大表示越难走, ...
- 洛谷P4197 Peaks (Kruskal重构树)
读题,只经过困难值小于等于x的路径,容易想到用Kruskal重构树:又要查询第k高的山峰,我们选择用主席树求解. 先做一棵重构树,跑一遍dfs,重构树中每一个非叶子节点对应一段区间,我们开range[ ...
- Luogu_4197 Peaks
P4197 Peaks 并不会克鲁斯卡尔重构树,于是就写了离线算法. 使用了最小生成树,启发式合并treap 在最小生成树,克鲁斯卡尔算法 时 ,将询问一块处理.便可以保证询问时边的要求.然后利用平衡 ...
- kruscal重构树略解
我们先看一道题:Luogu P4197 Peaks 这道题珂以用启发式合并+主席树来做 那么强制在线呢?(bzoj 3551 [ONTAK2010]Peaks加强版) 离线做法就不行了 我们就要用一个 ...
随机推荐
- iOS交互h5— JavaScriptCore ---UIWebview
JavaScriptCore这个框架,从而让web页面和本地原生应用交互起来非常方便,而且使用此框架可以做到Android那边和iOS相对统一, web前端 在三端交互中,web前端开发人员来定义,让 ...
- UIImagePickerController本地图片视频,相机录像机使用
1.添加framework:MobileCoreServices 2.头:#import <MobileCoreServices/MobileCoreServices.h> 大致代码: U ...
- Java多态-如何理解父类引用指向子类对象
java多态,如何理解父类引用指向子类对象 要理解多态性,首先要知道什么是“向上转型”. 我定义了一个子类Cat,它继承了Animal类,那么后者就是前者是父类.我可以通过 Cat c = new ...
- WEB前端常用JavaScript代码整理
文章目录 html代码用JS动态加载进页面 JS判断用户访问的是PC还是mobile或者微信浏览器 判断浏览器的简单有效方法 点击某个div区域之外,隐藏该div 如何在手机上禁止浏览器的网页滚动 改 ...
- Java项目经验——程序员成长的钥匙
本文转载至:http://geek.csdn.net/news/detail/109880,像我这样的菜鸟应该多看几遍这样的文章,学起来才更加有动力和方向. Java就是用来做项目的!Java的主要应 ...
- linux vim 快捷键
vim命令模式输入a i o 这些命令进入插入模式 编辑模式命令模式输入双引号进入编辑模式 命令模式命令 命令 作用 :map Ctrl+V Ctrl+P I#<ESC> 自定义注释快捷键 ...
- mvc5中重命名项目的名称后,出现"找到多个与名为“Home”的控制器匹配的类型"
1.已把项目中所有的Webapplication1改为了MvcMovie,但是运行后,还是报错: 找到多个与名为“Home”的控制器匹配的类型 2.已重新生成解决方安,还是不行. 解决方法:把bin文 ...
- 【 PostgreSQL】后台周期执行函数实例(shell+crontab)
工作中常见函数后台周期执行的情况,Oracle有job实现,gp数据库可以通过shell+crontab实现.流程如下: gpadmin用户下创建函数sh脚本. 将sh挂在crontab任务上 ### ...
- MySQL · 数据恢复 · undrop-for-innodb
Ref:https://www.aliyun.com/jiaocheng/1109809.html 摘要: 简介 undrop-for-innodb 是针对 innodb 的一套数据恢复工具,可以从 ...
- php数据结构之二叉树
树是一种比较重要的数据结构, 尤其是二叉树.二叉树是一种特殊的树,在二叉树中每个节点最多有两个子节点,一般称为左子节点和右子节点(或左孩子和右孩子),并且二叉树的子树有左右之 分,其次序不能任意颠倒. ...