ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【YbtOJ#482】爬上山顶

2021-02-17 16:33:57  阅读:238  来源: 互联网

标签:nxt 山顶 int YbtOJ top reg ans 482 10


题目

题目链接:https://www.ybtoj.com.cn/contest/116/problem/2

\(n\leq 5\times 10^5,x,y\leq 10^6\)。

思路

考虑求出点 \(i\) 左右分别能看到的最高点,然后在两者之间取最大值。
以左边为例,可以发现肯能造成贡献的一定位于上凸壳上,然后点 \(i\) 被贡献到的其实就是我们把点 \(i\) 插入到单调栈并维护好之后,单调栈中栈顶第二个元素。
求好了点 \(i\) 能看到的最高点 \(\text{nxt}_i\),接下来求点 \(i\) 到山顶的步数。
我们把点按照 \(\text{nxt}_i\) 的高度从大到小排序(高度相同右边在前),然后依次插入 set 中,每次插入前在 set 中找到这个点 \(x\) 前进方向上遇到的第一个点 \(y\),那么 \(x\) 在走到 \(y\) 之后就会向 \(\text{nxt}_y\) 走。那么显然 \(ans_x=ans_y+|x-y|\)。其实类似一个拓扑排序的过程。
时间复杂度 \(O(n\log n)\)。

代码

#include <bits/stdc++.h>
#define reg register
using namespace std;
typedef long long ll;

const int N=500010,Inf=1e9;
int n,rt,top,X[N],Y[N],st[N],nxt[N];
ll ans[N];

int read()
{
	int d=0; char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

void write(ll x)
{
	if (x>9) write(x/10);
	putchar(x%10+48);
}

struct node
{
	int id,nxt;
}b[N];

bool cmp(node x,node y)
{
	return (Y[x.nxt]==Y[y.nxt])?(x.nxt<y.nxt):(Y[x.nxt]>Y[y.nxt]);
}

double slope(int i,int j)
{
	return 1.0*(Y[j]-Y[i])/(X[j]-X[i]);
}

void solve()
{
	for (;top;top--) st[top]=0;
	for (reg int i=1;i<=n;i++)
	{
		while (top>1 && slope(st[top],st[top-1])<slope(st[top],i))
			st[top]=0,top--;
		st[++top]=i;
		int j=st[top-1];
		if (Y[j]>=Y[nxt[i]]) nxt[i]=j;
	}
}

void flip()
{
	for (reg int i=1;i<=n/2;i++)
	{
		swap(X[i],X[n-i+1]); swap(Y[i],Y[n-i+1]);
		swap(nxt[i],nxt[n-i+1]);
	}
	for (reg int i=1;i<=n;i++)
	{
		if (nxt[i]) nxt[i]=n-nxt[i]+1;
		X[i]=n-X[i]+1;
	}
	rt=n-rt+1;
}

void dp()
{
	for (reg int i=1;i<=n;i++)
		b[i]=(node){i,nxt[i]};
	sort(b+1,b+1+n,cmp);
	set<int> s;
	s.insert(0); s.insert(Inf);
	for (reg int i=1;i<=n;i++)
	{
		int j=b[i].id,k=b[i].nxt;
		if (j==rt) continue;
		if (k<j)
		{
			int p=*(--s.lower_bound(j));
			if (p<=k) ans[j]=ans[k]+j-k;
				else ans[j]=ans[p]+j-p;
		}
		else
		{
			int p=*s.upper_bound(b[i].id);
			if (p>=k) ans[j]=ans[k]+k-j;
				else ans[j]=ans[p]+p-j;
		}
		s.insert(j);
	}
}

int main()
{
	freopen("mountain.in","r",stdin);
	freopen("mountain.out","w",stdout);
	n=read();
	for (reg int i=1;i<=n;i++)
	{
		X[i]=read(); Y[i]=read();
		if (Y[i]>=Y[rt]) rt=i;
	}
	solve(); flip(); solve(); dp();
	for (reg int i=n;i>=1;i--)
		write(ans[i]),putchar(10);
	return 0;
}

标签:nxt,山顶,int,YbtOJ,top,reg,ans,482,10
来源: https://www.cnblogs.com/stoorz/p/14409099.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有