您的位置:首页 > 其它

bzoj 3958: [WF2011]Mummy Madness (扫描线+线段树)

2017-04-25 08:49 330 查看

题目描述

传送门

题解

二分一个移动的时间。然后每个木乃伊和自己能到达的区域是一个正方形。

判断自己能到达的区域是否完全被木乃伊所能到达的区域覆盖即可。

有些细节需要注意:

(1) 离散化的时候要插入中间点,否则离散完了不相邻的点都相邻了。

(2) 线段树区间修改的时候不下放标记,对于一个区间如果标记>0,那么答案就是区间的长度,这样子标记都被保留了,删除的时候可以直接删。

(3)需要注意自己能到达的边界,离散的时候要加入-mid,mid。

(4)这道题因为会做很多次,每次清数组会很慢,所以可以打lazy标记。

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define N 400003
using namespace std;
int dx
,dy
,cnt,tr[N*4],sum[N*4],lazy[N*4],n;
struct data{
int opt,val,x,l,r;
}q
;
struct node{
int x,y;
}a
;
void update(int now,int l,int r)
{
if (tr[now]>0) sum[now]=r-l+1;
else sum[now]=sum[now<<1]+sum[now<<1|1];
}
void clear(int now)
{
tr[now]=sum[now]=0;
lazy[now]=1;
}
void pushdown(int now)
{
if (lazy[now]) {
clear(now<<1);
clear(now<<1|1);
lazy[now]=0;
}
}
void query(int now,int l,int r,int ll,int rr,int v)
{
pushdown(now);
if (ll<=l&&r<=rr) {
tr[now]+=v; update(now,l,r);
return;
}
int mid=(l+r)/2;
//pushdown(now);
if (ll<=mid) query(now<<1,l,mid,ll,rr,v);
if (rr>mid) query(now<<1|1,mid+1,r,ll,rr,v);
update(now,l,r);
}
int cmp(data a,data b)
{
return a.x<b.x||a.x==b.x&&a.opt<b.opt;
}
bool check(int mid)
{
clear(1);
int cntx=0,cnty=0; cnt=0;
for (int i=1;i<=n;i++) {
if (a[i].x+mid<-mid||a[i].y+mid<-mid) continue;
if (a[i].x-mid>mid||a[i].y-mid>mid) continue;
++cnt; q[cnt].x=max(a[i].x-mid,-mid); q[cnt].l=max(a[i].y-mid,-mid);
q[cnt].r=min(a[i].y+mid,mid); q[cnt].val=1; q[cnt].opt=1;
dx[++cntx]=q[cnt].x; dy[++cnty]=q[cnt].l; dy[++cnty]=q[cnt].r;
++cnt; q[cnt].x=min(a[i].x+mid+1,mid+1); q[cnt].l=q[cnt-1].l; q[cnt].r=q[cnt-1].r; q[cnt].val=-1; q[cnt].opt=1;
dx[++cntx]=q[cnt].x; dy[++cnty]=max(q[cnt].l-1,-mid); dy[++cnty]=min(q[cnt].r+1,mid);
}
++cnt; q[cnt].x=-mid; q[cnt].l=-mid; q[cnt].r=mid; q[cnt].opt=2;
++cnt; q[cnt].x=mid; q[cnt].l=-mid; q[cnt].r=mid; q[cnt].opt=2;
dx[++cntx]=-mid; dx[++cntx]=mid; dy[++cnty]=-mid; dy[++cnty]=mid;
sort(dx+1,dx+cntx+1); sort(dy+1,dy+cnty+1);
cntx=unique(dx+1,dx+cntx+1)-dx-1;
cnty=unique(dy+1,dy+cnty+1)-dy-1;
for (int i=1;i<=cnt;i++)
q[i].x=lower_bound(dx+1,dx+cntx+1,q[i].x)-dx,
q[i].l=lower_bound(dy+1,dy+cnty+1,q[i].l)-dy,
q[i].r=lower_bound(dy+1,dy+cnty+1,q[i].r)-dy;
int l=1; sort(q+1,q+cnt+1,cmp);
int t=lower_bound(dx+1,dx+cntx+1,mid)-dx;
for (int i=1;i<=t;i++) {
while (q[l].x<=i&&l<=cnt) {
if (q[l].opt==1) query(1,1,cnty,q[l].l,q[l].r,q[l].val);
l++;
}
if (sum[1]!=cnty) return false;
}
return true;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
int T=0;
while (true) {
scanf("%d",&n); T++;
if (n==-1) break;
int mx=0,mn=0;
for (int i=1;i<=n;i++) {
scanf("%d%d",&a[i].x,&a[i].y);
mx=max(mx,a[i].x); mx=max(mx,a[i].y);
mn=min(mn,a[i].x); mn=min(mn,a[i].y);
}
int l=1; int r=min(1000000,mx-mn+1); int ans=1000001;
while (l<=r) {
int mid=(l+r)/2;
if (check(mid)) ans=min(ans,mid),r=mid-1;
else l=mid+1;
}
if (ans==1000001) printf("Case %d: never\n",T);
else printf("Case %d: %d\n",T,ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  扫描线 线段树