【题解 P4197】 Peaks

Peaks

题目描述

在 Bytemountains 有 \(n\) 座山峰,每座山峰有他的高度 \(h_i\)。有些山峰之间有双向道路相连,共 \(m\) 条路径,每条路径有一个困难值,这个值越大表示越难走。

现在有 \(q\) 组询问,每组询问询问从点 \(v\) 开始只经过困难值小于等于 \(x\) 的路径所能到达的山峰中第 \(k\) 高的山峰,如果无解输出 \(-1\)

输入格式

第一行三个数 \(n,m,q\)
第二行 \(n\) 个数,第 \(i\) 个数为 \(h_i\)

接下来 \(m\) 行,每行三个整数 \(a,b,c\),表示从 \(a \to b\) 有一条困难值为 \(c\) 的双向路径。
接下来 \(q\) 行,每行三个数 \(v,x,k\),表示一组询问。

输出格式

对于每组询问,输出一个整数表示能到达的山峰中第 \(k\) 高的山峰的高度。

样例 #1

样例输入 #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

提示

数据规模与约定

对于 \(100\%\) 的数据,\(n \le 10^5\)\(0 \le m,q \le 5\times 10^5\)\(h_i,c,x \le 10^9\)

解题思路

看到要经过边都要小于等于 \(x\) ,我们可以想到 \(kruskal\) 重构树。
对原图建一棵重构树,其结构为原节点在叶子,新建的节点代表的权值即为替代的边权。
采用欧拉序的思想,如果我们只对叶子编号的话,那么从某个点开始经过边权小于等于 \(x\) 的边的点集的编号是连续的。
那么每次求答案,我们可以先用倍增跳到重构树上一个节点,使得其为非叶子节点中点权小于等于 \(x\) 的点里面最高的,那么这颗节点的子树的叶子即为原图上按题目要求能到达的点。
编号是连续的,一段区间求 \(k\) 大,用主席树即可。
时间复杂度 \(O(nlogn)\)

Code

#include<bits/stdc++.h>
using namespace std;
struct edge
{
	int x,y,z;
}ed[500005];
struct datay
{
	int lc,rc,v;
}a[5000005];
int n,num,m,v[200005],m1,ft[200005],dfn[200005],out[200005],f[200005][21],f1[200005][21],re[200005],d[100005],num1,root[100005];
vector<int> t[200005];
map<int,int> p;
set<int> g;
bool cmp(edge q,edge w)
{
	return q.z<w.z;
}
int check(int x)
{
	if(ft[x]!=x)ft[x]=check(ft[x]);
	return ft[x];
}
void dfs(int x,int y)
{
	f[x][0]=ft[x]=y;
	if(t[x].size()==0)
	{
		dfn[x]=out[x]=++num;
		return;
	}
	dfn[x]=num+1;
	for(int i=0;i<t[x].size();i++)
	{
		if(t[x][i]==y)continue;
		dfs(t[x][i],x);
		f1[t[x][i]][0]=v[x];
	}
	out[x]=num;
	return;
}
int build(int l,int r)
{
	if(l==r)
	{
		return (++num1);
	}
	int mid=(l+r)>>1,h=++num1;
	a[h].lc=build(l,mid);
	a[h].rc=build(mid+1,r);
	return h;
}
int dijah(int x,int l,int r,int k,int v)
{
	int h=++num1;
	a[h]=a[x];
	if(l==r)
	{
		a[h].v++;
		return h;
	}
	int mid=(l+r)>>1;
	if(k<=mid)a[h].lc=dijah(a[x].lc,l,mid,k,v);
	else a[h].rc=dijah(a[x].rc,mid+1,r,k,v);
	a[h].v=a[a[h].lc].v+a[a[h].rc].v;
	return h;
}
int gaia(int x1,int x2,int l,int r,int k)
{
	if(l==r)return l;
	int mid=(l+r)>>1;
	if(a[a[x2].rc].v-a[a[x1].rc].v>=k)return gaia(a[x1].rc,a[x2].rc,mid+1,r,k);
	return gaia(a[x1].lc,a[x2].lc,l,mid,(k-(a[a[x2].rc].v-a[a[x1].rc].v))); 
}
int main()
{
	int x,y,z,o,g1=0;
	scanf("%d%d%d",&n,&m,&m1);
	o=n;
	for(int i=1;i<=n;i++)scanf("%d",&v[i]),g.insert(v[i]);
	set<int>::iterator q=g.begin();
	for(;q!=g.end();q++)
	{
		p[*q]=++g1;
		d[g1]=*q;
	} 
	for(int i=1;i<=n;i++)v[i]=p[v[i]];
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].z);
	}
	sort(ed+1,ed+m+1,cmp);
	for(int i=1;i<=2*n;i++)ft[i]=i;
	for(int i=1;i<=m;i++)
	{
		x=check(ed[i].x);
		y=check(ed[i].y);
		if(x!=y)
		{
			t[++o].push_back(x);
			t[o].push_back(y);
			ft[x]=ft[y]=o;
			v[o]=ed[i].z;
		}
	}
	for(int i=0;i<=20;i++)f1[o][i]=1e9+5;
	dfs(o,0);
	for(int i=1;i<=20;i++)
	{
		for(int j=1;j<=o;j++)f[j][i]=f[f[j][i-1]][i-1],f1[j][i]=max(f1[j][i-1],f1[f[j][i-1]][i-1]);
	}
	for(int i=1;i<=n;i++)
	{
		re[dfn[i]]=i;
	}
	root[0]=build(1,n);
	for(int i=1;i<=n;i++)
	{
		root[i]=dijah(root[i-1],1,n,v[re[i]],1);
	}
	for(int i=1;i<=m1;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		for(int j=20;j>=0;j--)
		{
			if(f1[x][j]<=y)x=f[x][j];
		}
		if(out[x]-dfn[x]+1<z)
		{
			printf("-1\n");
			continue;
		}
		g1=gaia(root[dfn[x]-1],root[out[x]],1,n,z);
		printf("%d\n",d[g1]);
	}
	








  return 0;
}
posted @ 2024-01-24 13:22  dijah  阅读(23)  评论(0编辑  收藏  举报