您的位置:首页 > 其它

【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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: