BZOJ3755 : Pty爬山
l[i],r[i]表示站在i点往左往右走能看到的最高峰,用栈维护凸壳求出
h[i]表示i点能看到的最高峰的高度
a[i],b[i]表示i点往左往右走时反悔的点,即第一个h[j]>h[i]的j,用单调栈求出
然后建树DFS一遍求出答案
#include<cstdio> #define N 200010 typedef long long ll; int n,i,x[N],y[N],l[N],r[N],q[N],a[N],b[N],t,g[N],nxt[N],v[N],ed,d[N],f[N];ll Y[N],h[N]; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} inline int abs(int x){return x>0?x:-x;} void dfs(int x){for(int i=g[x];i;i=nxt[i])f[v[i]]=f[x]+abs(x-v[i]),dfs(v[i]);} int main(){ read(n); for(y[0]=y[n+1]=-1,i=1;i<=n;i++)read(x[i]),read(y[i]),Y[i]=1000000LL*y[i]+i; for(q[t=0]=n,i=n-1;i;q[++t]=i--){ while(t&&(ll)(y[q[t]]-y[i])*(x[q[t-1]]-x[q[t]])<=(ll)(y[q[t-1]]-y[q[t]])*(x[q[t]]-x[i]))t--; r[i]=q[t]; } for(q[t=0]=1,i=2;i<=n;q[++t]=i++){ while(t&&(ll)(y[q[t]]-y[i])*(x[q[t-1]]-x[q[t]])>=(ll)(y[q[t-1]]-y[q[t]])*(x[q[t]]-x[i]))t--; l[i]=q[t]; } for(i=1;i<=n;i++){ if(Y[i]>Y[l[i]])l[i]=0; if(Y[i]>Y[r[i]])r[i]=n+1; h[i]=Y[i]; if(Y[l[i]]>h[i])h[i]=Y[l[i]],d[i]=1; if(Y[r[i]]>h[i])h[i]=Y[r[i]],d[i]=2; } h[0]=h[n+1]=1LL<<60; for(q[t=0]=0,i=1;i<=n;q[++t]=i++){ while(h[i]>h[q[t]])t--; a[i]=q[t]>l[i]?q[t]:l[i]; } for(q[t=0]=n+1,i=n;i;q[++t]=i--){ while(h[i]>h[q[t]])t--; b[i]=q[t]<r[i]?q[t]:r[i]; } for(i=1;i<=n;i++){ if(!d[i])t=i; if(d[i]==1)add(a[i],i); if(d[i]==2)add(b[i],i); } for(dfs(t),i=1;i<=n;i++)printf("%d\n",f[i]); return 0; }