【JZOJ 3401】Pty爬山
2016-05-22 10:32
295 查看
Description
坐标系里有N个点,保证他们的x坐标递增,它们互相连接形成一些连续的线段。每个点会向自己的位置能看到的最高点(能看到指视线不经过其它线段)沿着线段移动。若移动过程中到达的点能看到的最高点比原先的最高点高,则向新的最高点移动……若该点就是最高点则停止移动。求从每个点出发移动的步数。Analysis
题目没有说明,但是数据是三点共线是可以被看见的(这证明了地球不是圆的2333)。这道题我花了整场比赛去搞,结果比赛时只有10分QAQ.
首先预处理出每个点能够看到的最高点。正反各搜一遍,比较一下斜率就好了。O(n)解决。
然后一个直观的想法就是模拟走路的过程。但是这样最坏情况可以达到O(n3),于是爆炸。
显然地,无需如此暴力。
我们可以用一棵线段树,记录每个点能看到的最高点的高度。这样走的时候直接线段树查询,复杂度变成O(n2log2n),这样就能拿到60分了。
实际上,我们可以发现,这道题的图的关系还是比较显著的。我们只需让每个点能看到的最高点向该点连边。然后从全图最高点开始bfs一遍记录边权更新每个点的答案就好了。O(nlog2n),于是乎就能通过所有数据了。
Code
#include<cstdio> #include<cmath> #include<queue> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,b,a) for(int i=b;i>=a;i--) using namespace std; typedef double db; const int N=200010,M=N*2; int n,pos,b ,b1 ,b2 ,mx[N*4]; int tot,to[M],wei[M],next[M],last ,dis ; queue<int> q; struct point { int x,y; }a ; db slope(point a,point b){return (a.y-b.y)*1.0/(a.x-b.x);} void link(int u,int v,int w) { to[++tot]=v,wei[tot]=w,next[tot]=last[u],last[u]=tot; } void pre() { scanf("%d",&n); fo(i,1,n) scanf("%d %d",&a[i].x,&a[i].y); fd(i,n-1,1) b1[i]=i+1; b1 =n; fd(i,n-2,1) for(;slope(a[i],a[b1[b1[i]]])>=slope(a[i],a[b1[i]]);b1[i]=b1[b1[i]]) if(b1[i]==n) break; fo(i,2,n) b2[i]=i-1; b2[1]=1; fo(i,3,n) for(;slope(a[i],a[b2[b2[i]]])<=slope(a[i],a[b2[i]]);b2[i]=b2[b2[i]]) if(b2[i]==1) break; fo(i,1,n) { b[i]=i; if(a[b1[i]].y>=a[b[i]].y) b[i]=b1[i]; if(a[b2[i]].y>a[b[i]].y) b[i]=b2[i]; } } void build(int v,int l,int r) { if(l==r) { mx[v]=a[b[l]].y; return; } int mid=(l+r)>>1; build(v*2,l,mid); build(v*2+1,mid+1,r); mx[v]=max(mx[v*2],mx[v*2+1]); } void findl(int v,int l,int r,int z) { if(mx[v]<z) return; if(l==r) { pos=min(pos,l); return; } int mid=(l+r)>>1; if(mx[v*2]>=z) findl(v*2,l,mid,z); else if(mx[v*2+1]>=z) findl(v*2+1,mid+1,r,z); } void findr(int v,int l,int r,int z) { if(mx[v]<z) return; if(l==r) { pos=max(pos,r); return; } int mid=(l+r)>>1; if(mx[v*2+1]>=z) findr(v*2+1,mid+1,r,z); else if(mx[v*2]>=z) findr(v*2,l,mid,z); } void find(int v,int l,int r,int x,int y,int z,bool p) { if(l==x && r==y) { if(p) findr(v,x,y,z); else findl(v,x,y,z); return; } int mid=(l+r)>>1; if(y<=mid) find(v*2,l,mid,x,y,z,p); else if(x>mid) find(v*2+1,mid+1,r,x,y,z,p); else find(v*2,l,mid,x,mid,z,p), find(v*2+1,mid+1,r,mid+1,y,z,p); } int val(int x,int y) { pos=y; if(x<y) { x++; find(1,1,n,x,y,a[y].y+1,0); return pos; } x--; find(1,1,n,y,x,a[y].y,1); return pos; } void bfs(int S) { q.push(S); dis[S]=0; while(!q.empty()) { int u=q.front();q.pop(); for(int i=last[u];i;i=next[i]) { int v=to[i]; dis[v]=dis[u]+wei[i]; q.push(v); } } } int main() { pre(); build(1,1,n); int root=1; fo(i,1,n) { if(i==b[i]) {root=i;continue;} int j=val(i,b[i]); link(j,i,abs(i-j)); } bfs(root); fo(i,1,n) printf("%d\n",dis[i]); return 0; }
相关文章推荐
- 计算机病毒实践总结二:简单动态分析
- Spring MVC学习笔记——JSR303介绍及最佳实践
- 构建之法阅读笔记05
- Node.js 文件系统
- FZU NO.2150 Fire Game(枚举+BFS)
- OBIEE编辑报表比率向下取整问题
- java二维码qrcode生成代码下载,进行加密,解密,相对于最代码xiaoxiaot的更为简便
- java中字节数组与其他各类型的转换
- 卡方检验用于特征提取
- 图像算法研究---索引图像旋转缩放锯齿问题
- sparl ML使用TFIDF
- maven仓库--私服(Nexus的配置使用)
- ActivityManager: Warning: Activity not started, its current task has been brought to the front 的的问题
- ceph系统原理 细节 benchmark 不完全说明
- https 讲解
- 数据库----判别一个分解的无损连接性
- Java 多线程(二) Thread类与Runnable接口的关系
- 102. Binary Tree Level Order Traversal
- Struts2的常量配置
- Yii2.0 模态弹出框+ajax提交表单