GDOI2014模拟pty爬山(mountain)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GDOI2014模拟pty爬山(mountain)相关的知识,希望对你有一定的参考价值。
pty爬山(mountain)
在Pty学校附近,有一座名之为岳之麓的高山。Pty很喜欢和(哔——)一起爬山。
山的平面模型如下:
山由一个顶点集:A1,A2…An给定,保证Ai的x单调递增。我们将Ai和Ai+1之间连上线段,表示山的某一段。如下图所示:
Pty想要爬到这座山的最高的顶点,当两个顶点的高度相同时,我们认为x比较大的顶点要高一些。Pty不是盲人,所以他将会在爬山时采取一些策略,使得他能够尽量快的到达最高的顶点。
Pty从初始的顶点出发,往左右看去,他将朝他能够看到的最高的顶点方向走去。当走到每一个顶点时,他都会重新观察,如果这时看到的顶点比之前看到的顶点还要高,那么他将选择此时看到的顶点走去,直到他到达最高点为止。如果顶点A能够看到顶点B,则线段AB没有严格穿过山的内部。
例如上图中:Pty从A4点出发。他能够看到的最高点是A6,所以他将会向右侧走去。当他到达A5号点时,能够看到A1点比A6点更高,所以他会调转方向,向左侧走去。由于A1是最高的顶点,所以他将一直往左侧走,直到到达A1为止。
Pty想知道从每一个顶点出发,分别需要走过多少段才能到达最高点。例如上图中从A4出发需要走过5段才能到达最高点。
输入格式:
第一行输入n,表示n个顶点。接下来n行,每行两个整数xi, yi,表示第i个顶点的坐标。
输入保证xi单调递增。
输出格式:
输出共n行:第i行表示从第i个顶点出发走到最高点需要经过多少段。样例输入:
5
1 5
2 4
3 9
4 0
5 2
样例输出:
2
1
0
1
2
数据范围:
30%的数据满足:n<= 10060%的数据满足:n <= 50000
100%的数据满足:n<=200000, xi<=10^6, yi <= 10^6
i一定能看见i?1
i如果看不见l[i?1],那么一定看不见1~l[i?1]
i如果看得见l[i?1]且看不见l[l[i?1]],那么l[i]=l[i?1]
所以可以用动态规划在O(n)内求出i点向左、向右能看到的最高点。
然后再处理出每个点出发时能看到的最高点,将它按照y与x从小到大排序
按照排序后的顺序,高度从低到高的点依次做。这个点该往哪边走,双向链表中对应方向上与之相邻的点就是要找的点,然后把做过的点删掉即可。(妙!
发现形成了一棵以最高点为根的树,dfs求出答案即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 const int N=200010; 7 struct node{ 8 int next,to; 9 }edge[N]; 10 struct no{ 11 int y,z,to; 12 }a[N]; 13 int n,l[N],r[N],x[N],y[N],head[N],s=0,L[N],R[N],f[N]; 14 inline void del(int x) 15 { 16 R[L[x]]=R[x]; 17 L[R[x]]=L[x]; 18 } 19 inline bool see(int a,int b,int c)//a>b>c 20 { 21 double s=(0.0+y[a]-y[c])/(x[a]-x[c]+0.0); 22 s=s*(x[b]-x[c])+y[c]; 23 if(y[b]<=s) return true; 24 else return false; 25 } 26 inline void unite(int x,int y) 27 { 28 s++; 29 edge[s].to=y; 30 edge[s].next=head[x]; 31 head[x]=s; 32 } 33 inline void dfs(int x,int dis) 34 { 35 f[x]=dis; 36 for(int i=head[x];i;i=edge[i].next) dfs(edge[i].to,dis+abs(x-edge[i].to)); 37 } 38 inline int abs(int x){return (x>0?x:-x);} 39 inline bool cmp(no a,no b){if(a.y!=b.y) return a.y<b.y;return a.to<b.to;} 40 int main() 41 { 42 int mx=-10000000,rec,p,et; 43 scanf("%d",&n); 44 for(int i=1;i<=n;i++) 45 { 46 scanf("%d%d",&x[i],&y[i]); 47 if(mx<=y[i]){mx=y[i];rec=i;} 48 } 49 for(int i=2;i<=n;i++) 50 { 51 l[i]=i-1; 52 while(y[l[i]]<=y[l[l[i]]]&&see(l[l[i]],l[i],i)&&l[i]!=1) l[i]=l[l[i]]; 53 } 54 r[n]=n+1; 55 for(int i=n-1;i>=1;i--) 56 { 57 r[i]=i+1; 58 while(y[r[i]]<=y[r[r[i]]]&&see(r[r[i]],r[i],i)&&r[i]!=n) r[i]=r[r[i]]; 59 } 60 for(int i=1;i<=n;i++) 61 { 62 R[i]=i+1; 63 L[i]=i-1; 64 a[i].z=i; 65 if(y[r[i]]>=y[l[i]]) a[i].to=r[i]; 66 else a[i].to=l[i]; 67 a[i].y=y[a[i].to]; 68 } 69 a[rec].y=2000000000; 70 sort(a+1,a+n+1,cmp); 71 for(int i=1;i<n;i++) 72 { 73 p=a[i].z; 74 if(a[i].to<p) et=L[p]; 75 else et=R[p]; 76 unite(et,p); 77 del(p); 78 } 79 dfs(rec,0); 80 for(int i=1;i<=n;i++) printf("%d\n",f[i]); 81 return 0; 82 }
以上是关于GDOI2014模拟pty爬山(mountain)的主要内容,如果未能解决你的问题,请参考以下文章
P1561 [USACO12JAN]爬山Mountain Climbing
洛谷—— P1561 [USACO12JAN]爬山Mountain Climbing