bzoj 3755: Pty爬山

称关键点为使其改变目标的点,从一个点出发,到达的关键点是确定的,且如果一条路径上到达某个点为关键点,那么之后的路径和从这个点出发的路径相同,所以我们就要找出每个点出发走到的下一个关键点。
首先找到每个点能看到的最高的山峰,维护每个点左面的上凸壳,右边的上凸壳,那么它能看到的最高的山峰就是这两个下凸壳的最后一个点中较高的点,而要寻找的关键点一定在这个点和那个较高的点之间。
之后,把所有点按照到达的点的高度从大到小排序,枚举每个点,找它和它能看到的最高山峰之间的已经被枚举的离它最近的点,就是关键点。
   
   
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md
#define N 200010
using namespace std;
struct yts { int x,t,ne;} e[N];
struct PP { ll x,y;} p[N];
ll ans[N];
set<int> st;
int v[N],q[N],L[N],R[N],num,g[N],h[N];
PP operator - (PP a,PP b) { return (PP){a.x-b.x,a.y-b.y};}
ll operator / (PP a,PP b) { return a.x*b.y-a.y*b.x;}
void put(int x,int y)
{
num++; e[num].x=x; e[num].t=y;
e[num].ne=v[x]; v[x]=num;
}
 
void dfs(int x,ll dis)
{
ans[x]=dis;
for (int i=v[x];i;i=e[i].ne)
dfs(e[i].t,dis+abs(x-e[i].t));
}
 
bool cmp (int x,int y) { return p[g[x]].y==p[g[y]].y?g[x]>g[y]:p[g[x]].y>p[g[y]].y;}
 
int main()
{
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld%lld",&p[i].x,&p[i].y);
int top=0;
for (int i=1;i<=n;i++)
{
while (top>1&&(p[i]-p[q[top-1]])/(p[q[top]]-p[q[top-1]])<=0) top--;
if (top&&p[q[top]].y>p[i].y) L[i]=q[top];
q[++top]=i;
}
top=0;
for (int i=n;i;i--)
{
while (top>1&&(p[i]-p[q[top-1]])/(p[q[top]]-p[q[top-1]])>=0) top--;
if (top&&p[q[top]].y>=p[i].y) R[i]=q[top];
q[++top]=i;
}
int root;
for (int i=1;i<=n;i++)
{
if (L[i]&&(!R[i]||p[L[i]].y>p[R[i]].y)) g[i]=L[i];
else if (R[i]) g[i]=R[i];
else root=i;
}
p[0].y=inf;
for (int i=1;i<=n;i++) h[i]=i;
sort(h+1,h+n+1,cmp);
for (int i=1;i<=n;i++)
{
int x=h[i];
if (!g[x]) { st.insert(x); continue;}
if (g[x]<x)
{
set<int>::iterator it =--st.lower_bound(x);
put(*it,x);
}
else
{
set<int>::iterator it=st.upper_bound(x);
put(*it,x);
}
st.insert(x);
}
dfs(root,0);
for (int i=1;i<=n;i++) printf("%lld\n",ans[i]);
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值