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 加强版的主要内容,如果未能解决你的问题,请参考以下文章

P4197 Peaks

P4197 Peaks

[Kruskal重构树][主席树] Luogu P4197 Peaks

Luogu_4197 Peaks

BZOJ 3545ONTAK 2010Peaks & BZOJ 3551ONTAK 2010Peaks加强版 Kruskal重构树

bzoj3545 && bzoj3551 Peaks(离线版&&在线版)