您的位置:首页 > 其它

CF286D/bzoj-4223 Tourists

2015-12-04 14:10 363 查看
题意:

直角坐标系下,在一些时刻会有两个游客分别同时从点 (−1, 0) 和 (1, 0) 出发;

每一对游客每秒都向 y 轴正方向前进一个单位长度;

在一些时刻墙会出现,墙 (li,ri) 是一条在点 (0,li) 和(0,ri) 之间的线段;

给出 m 堵墙的出现时间 ti 以及出现的区间,给出 n 对游客出发时间 qi;

请求出对于每一对游客有多长时间无法彼此望见。

n,m<=10^5,li,ri,ti<=10^9;

UPD:发现了在大视野的双倍经验!

题解:

自己YY不动这个扫描线,所以去vfk的题解里膜了一个扫描线姿势;

因为墙出现了就不再消失,所以考虑将墙的li,ri看成纵坐标,将时间看成横坐标,那么就得到了一个没有上界的矩形;

而多个墙并起来就是一个无上界的奇怪图形,我们要处理出这个图形的所有顶点;


(此图及以下图片都是样例2)

处理的方法就是用一个堆维护当前扫到的所有点中时间的最小值,然后从左往右扫,扫到一个边在边界上的边就处理一下什么的;

这个点数目显然不会太多,最多在m*4的级别;

为了方便处理我在最上面(0x7f7f7f7f)加了一个长条矩形作为边界,但是注意这个要足够高,0x3f3f3f3f会挂;

处理了所有的点之后,对于时间pi出发的旅客,答案就是直线y=x+pi在这个图形上截的x轴距离;



正确性YY一下还是显然的,然后从右下向左上用一条y=x的直线扫并计算答案就可以了;

算法过程中只需要记录now当前的答案,以及cnt当前可以增长答案的线段个数;

每次经过询问就更新答案,经过端点时更改线段个数;

这些扫描的时间复杂度都是线性的,然而排序是O(nlogn)哦。。。

代码:

#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
#define pr pair<int,int>
using namespace std;
struct wall
{
int no,x,t;
friend bool operator <(wall a,wall b)
{
if(a.x!=b.x)
return a.x<b.x;
return a.t<b.t;
}
}w[N<<1];
struct Point
{
int x,y,type,no;
friend bool operator <(Point a,Point b)
{
return a.y-a.x<b.y-b.x;
}
}p[N*5];
int tot;
int L
,R
,T
;
priority_queue<pr,vector<pr>,greater<pr> >q;
bool vis
;
int ans
;
int main()
{
int n,m,i,k,now,cnt;
scanf("%d%d",&m,&n);
for(i=1;i<=n;i++)
{
scanf("%d%d%d",L+i,R+i,T+i);
w[i<<1].no=w[i<<1|1].no=i;
w[i<<1].x=L[i],w[i<<1|1].x=R[i];
w[i<<1].t=w[i<<1|1].t=T[i];
}
sort(w+2,w+n+n+2);
q.push(pr(0x7f7f7f7f,0));
vis[0]=1;
for(i=2;i<=n+n+1;i++)
{
if(!vis[w[i].no])
{
while(!q.empty()&&!vis[q.top().second])
q.pop();
if(!q.empty()&&w[i].t<q.top().first)
{
tot++;
p[tot].x=w[i].x;
p[tot].y=q.top().first;
p[tot].type=1;
tot++;
p[tot].x=w[i].x;
p[tot].y=w[i].t;
p[tot].type=-1;
}
q.push(pr(w[i].t,w[i].no));
vis[w[i].no]=1;
}
else
{
while(!q.empty()&&!vis[q.top().second])
q.pop();
if(q.top().second==w[i].no)
{
q.pop();
while(!q.empty()&&!vis[q.top().second])
q.pop();
tot++;
p[tot].x=w[i].x;
p[tot].y=w[i].t;
p[tot].type=1;
tot++;
p[tot].x=w[i].x;
p[tot].y=q.top().first;
p[tot].type=-1;
}
vis[w[i].no]=0;
}
}
for(i=1;i<=m;i++)
{
scanf("%d",&k);
tot++;
p[tot].type=0;
p[tot].x=0;
p[tot].y=k;
p[tot].no=i;
}
sort(p+1,p+tot+1);
for(i=1,now=0,cnt=0;i<=tot;i++)
{
now+=cnt*(p[i].y-p[i].x-p[i-1].y+p[i-1].x);
cnt+=p[i].type;
if(!p[i].type)
ans[p[i].no]=now;
}
for(i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Codeforces 扫描线