首页 > 其他分享 >【题解 P4197】 Peaks

【题解 P4197】 Peaks

时间:2024-01-24 13:22:06浏览次数:31  
标签:10 return Peaks int 题解 ++ rc P4197 200005

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;
}

标签:10,return,Peaks,int,题解,++,rc,P4197,200005
From: https://www.cnblogs.com/dijah/p/17984474

相关文章

  • 【题解 P3293】 美味
    [SCOI2016]美味题目描述一家餐厅有\(n\)道菜,编号\(1,2,\ldots,n\),大家对第\(i\)道菜的评价值为\(a_i\)。有\(m\)位顾客,第\(i\)位顾客的期望值为\(b_i\),而他的偏好值为\(x_i\)。因此,第\(i\)位顾客认为第\(j\)道菜的美味度为\(b_i\oplus(a_j+x_i)\),\(\opl......
  • 2024寒假集训 进阶训练赛 (六)部分题解
    A统计单词数题解注意是否是单词。CODECPP#include<iostream>#include<string>#include<algorithm>usingnamespacestd;intmain(){stringword,article;getline(cin,word);getline(cin,article);//转换为小写字母transform(word.beg......
  • Romberg 数值积分算法+P3779 题解(马上写完)
    Romberg算法吊打Simpson的且不玄学(没有什么十五倍)的数值积分算法。缺点是过程复杂一点,但是只体现在证明上,代码很短。铺垫算法梯形求积公式公式\[\int_a^bf(x)dx\approx\frac{(f(a)+f(b))(b-a)}2\\\text{令}(1)=\frac{(f(a)+f(b))(b-a)}2\]计算梯形求积公式的误差......
  • 前端打包后上传至服务器,发现css样式都未生效,查看请求preview预览格式不正确问题解决
    参考:https://blog.csdn.net/wzj_110/article/details/112850811 我的问题前端打包后上传至服务器,发现css样式都未生效,查看css请求,发现preview预览格式不正确,Response-Headers里的Content-type未对应 原因服务器的nginx配置中, mime.types文件缺失。 原理 MIME:Multip......
  • P2627 [USACO11OPEN] Mowing the Lawn G ( [USACO Open11] 修剪草坪/P2034 选择数字 )题
    P2627[USACO11OPEN]MowingtheLawnG搬运工单调队列优化DP简单题,和P2034重了题意:给定一行\(n\)个非负整数\(a_1\cdotsa_n\)。现在你可以选择其中若干个数,但不能有超过\(k\)个连续的数字被选择。你的任务是使得选出的数字的和最大。(直接抄的2034)正着考虑发现很麻烦,......
  • LOJ3990/LG9602 IOI2023 足球场 题解 (区间DP+精简无用状态)
    首先考虑一个足球场长啥样才是合法的。发现一个点能只拐弯一次到达另一个点,可以分为两种情况:先左右走,再上下走或先上下走,后左右走。无论哪种情况,都要求我们走一步使得和目标点一个轴相同,再走一步使得另一个轴也相同,所以加入把每一行选择的格子看成一个区间(因为如果不连续显然是......
  • CF327C Magic Five 题解
    CF327CMagicFive搬运工单调队列优化DP加等比数列求和首先\(5\)的倍数要求末尾是\(0\)或\(5\)所以我们只用看给定字符串的\(0\)和\(5\)就好,我们钦定他是最终的数的末尾。在他之前的选择删掉,在他之后的全部删掉,方案数就是\(2^{pow-1}\),答案累加就可以了。容易想到......
  • P2254 [NOI2005] 瑰丽华尔兹 题解
    P2254[NOI2005]瑰丽华尔兹搬运工单调队列优化DP还是先朴素,设\(f_{t\i\j\d}\)表示在第\(t\)个时刻,在\(i,j\)位置上,上一步是停留还是滑动的最大步数。这个就是四个方向随便转移。\(T_{max}=4*10^4\)这么做肯定不行。发现\(k\)很小,只有\(200\),所以不妨让\(k\)......
  • P2569 [SCOI2010] 股票交易 题解
    P2569[SCOI2010]股票交易搬运工稍微复杂一点的单调队列优化DP直接设\(f_{i\j}\)表示在第\(i\)天,手上还剩\(j\)个股票时的最大收入。容易写出状态转移方程:\(f_{i\j}=max\{f_{k\t}+(t-j)\cdotw\}\),这样不好看,我们可以拆成这样的形式:\[f_{i\j}=max\{f_{k\t}+t\cdo......
  • P4899 [IOI2018] werewolf 狼人 题解
    因为我记忆力不好,经常遇到之前做过的题一下子想不起来,所以打算基本上给每个比较有意思的题写题解,同时造福后代。这是werewolf,它是furry,很可爱题意:一张无向图,点有点权,每次询问从\(u\)到\(v\)的路径中,是否存在一条先走点权大于等于\(L\),再走点权小于等于\(R\)的路径。思路......