P4197 Peaks&&P7834 [ONTAK2010] Peaks 加强版
Posted 斗奋力努
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4197 Peaks&&P7834 [ONTAK2010] Peaks 加强版相关的知识,希望对你有一定的参考价值。
P4197 Peaks
P7834 [ONTAK2010] Peaks 加强版
加强版:就是多记录一个lastans,同时查询时v、x、k根据式子变换就行了
题意:每次从山v开始,经过困难值不超过x的路径所能到达的山峰中,第k高的山峰的高度。
思路:Kruskal重构树跑dfs序建主席树找第k大(0…0)
因为问题中是困难值不超过x的路径,也就是最大值(极限值)的最小值,所以我们用Kruskal重构树时是最小生成树;
随后就是再dfs序中找第k大值了,没有k个数字输出-1。上主席树就行了。
//https://www.luogu.com.cn/problem/P4197 kruskal重构树+主席树
#include<bits/stdc++.h>
using namespace std;
const int N=8e5+5;
int n,m,q,h[N];
int to[N],ne[N],val[N],fir[N],idx,cnt;
int fa[N],f[N][25];//树上倍增
int L[N],R[N],nu;//dfs序
int root[N],id,sz;//sz为离散化后num大小
vector<int>num;
struct nodeint ls,rs,sum;tr[N*30];//主席树
struct Edgeint u,v,w;edge[N];
bool cmp(Edge l,Edge r)return l.w<r.w;//最小生成树
void add(int u,int v)to[idx]=v;ne[idx]=fir[u];fir[u]=idx++;//链式前
int find(int x)return x==fa[x]?x:fa[x]=find(fa[x]);//并查集
void disc()//离散化
sort(num.begin(),num.end());
num.erase(unique(num.begin(),num.end()),num.end());
sz=num.size();
for(int i=1;i<=n;i++) h[i]=lower_bound(num.begin(),num.end(),h[i])-num.begin()+1;
void input()
memset(fir,-1,sizeof(fir));
scanf("%d%d%d",&n,&m,&q); cnt=n;//已经有n个点,下个节点编号从n+1起
for(int i=1;i<=n;i++) scanf("%d",&h[i]),num.push_back(h[i]);
for(int i=1;i<=m;i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
void Kruskal()
sort(edge+1,edge+m+1,cmp);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
int fu=find(edge[i].u),fv=find(edge[i].v),w=edge[i].w;
if(fu==fv) continue;
val[++cnt]=w;
fa[cnt]=fa[fu]=fa[fv]=cnt;
add(cnt,fu),add(cnt,fv);//节点cnt是fu、fv的父亲节点
int build(int l,int r)
int p=++id;
if(l==r) return p;
int mid=(l+r)>>1;
tr[p].ls=build(l,mid),build(mid+1,r);
return p;
int insert(int p,int l,int r,int x)//主席树板子,插数
int q=++id;
tr[q]=tr[p];
if(l==r)
tr[q].sum++;
return q;
int mid=(l+r)>>1;
if(x<=mid) tr[q].ls=insert(tr[p].ls,l,mid,x);
else tr[q].rs=insert(tr[p].rs,mid+1,r,x);
tr[q].sum=tr[tr[q].ls].sum+tr[tr[q].rs].sum;
return q;
void dfs(int u,int father)
f[u][0]=father;
for(int i=1;i<=22;i++) f[u][i]=f[f[u][i-1]][i-1];
L[u]=nu;
if(fir[u]==-1)//叶子节点,就加入
L[u]=++nu;
root[nu]=insert(root[nu-1],1,sz,h[u]);
for(int i=fir[u];~i;i=ne[i]) dfs(to[i],u);
R[u]=nu;
int query(int q,int p,int l,int r,int kth)//主席树板子,区间第k大
if(l==r) return l;
int sum=tr[tr[p].rs].sum-tr[tr[q].rs].sum;
int mid=(l+r)>>1;
if(kth<=sum) return query(tr[q].rs,tr[p].rs,mid+1,r,kth);
else return query(tr[q].ls,tr[p].ls,l,mid,kth-sum);
void Ac()
root[0]=build(1,sz);
dfs(cnt,0);
while(q--)
int v,x,k; scanf("%d%d%d",&v,&x,&k);
for(int i=22;i>=0;i--)
if(f[v][i]&&val[f[v][i]]<=x)//从x出发,也就是一颗包含x的子树,倍增找到子树的根
v=f[v][i];
if(tr[root[R[v]]].sum-tr[root[L[v]]].sum<k) puts("-1");
else printf("%d\\n",num[query(root[L[v]],root[R[v]],1,sz,k)-1]);
int main()
input();
disc();
Kruskal();
Ac();
以上是关于P4197 Peaks&&P7834 [ONTAK2010] Peaks 加强版的主要内容,如果未能解决你的问题,请参考以下文章
[Kruskal重构树][主席树] Luogu P4197 Peaks
BZOJ 3545ONTAK 2010Peaks & BZOJ 3551ONTAK 2010Peaks加强版 Kruskal重构树