【BZOJ3958】[WF2011]Mummy Madness 二分+扫描线+线段树

【BZOJ3958】[WF2011]Mummy Madness

Description

在2011年ACM-ICPC World Finals上的一次游览中,你碰到了一个埃及古墓。
不幸的是,你打开了坟墓之后,才发现这是一个坏主意:突然之间,原本空无一物的沙漠上已经爬满了暴躁的木乃伊。(如果你也沉睡几千年而突然被惊醒,你也会变得如此暴躁的。)(幸运的是,当你做完这道题的时候,你醒来了,发现你在弗罗里达的酒店里。那些木乃伊只是一场梦。)
面对这一大堆疯狂的木乃伊,你唯一的机会就是试图在他们抓到你之前逃跑。问题是:假如你与木乃伊永不疲倦,那么经过多长时间你会被木乃伊抓到?
我们把沙漠看成一个正方形的网格,你与木乃伊轮流移动(你走出第一步)。轮到你时,你可以移动到相邻的8个格子之一,或者站着不动。轮到木乃伊时,每个木乃伊会移动到其相邻的格子之一,使得他与你的欧几里得距离尽量小(假设你与木乃伊都站在格子的中心位置)。允许多个木乃伊同时占据同一个格子。
在每个单位时间内,你先做出移动,然后木乃伊做出移动。如果你与任何一个木乃伊站在同一位置,你会被抓住。当然,你试图尽量长时间避免被抓住。经过多少单位时间你会被抓住呢?
下图描述了你被4个木乃伊追逐的例子。H代表你的初始位置,而M代表木乃伊的初始位置。以你的初始位置为原点,则经过4个单位时间后,你被初始位置为(3,4)的木乃伊抓住。

Input

输入文件包含若干组数据。每组数据的第一行为一个数n(0≤n≤10^5),表示沙漠中木乃伊的个数。接下来n行,每行两个整数x y,表示初始时在(x,y)有一个木乃伊。x,y的绝对值均不超过10^6。你的初始位置是(0,0),保证一开始这里没有木乃伊。
输入文件以一行-1结束。

Output

对于每组测试数据,输出一行,包括它的编号和被抓住经过的最长时间(即你做出决策的次数);或输出"never",如果你有办法永远不被抓住。
请以样例输出的格式输出数据。

Sample Input

4
-3 5
3 4
-6 -2
1 -5
1
0 -1
-1

Sample Output

Case 1: 4
Case 2: never

HINT

对于100%的数据,n≤10^5

题解:容易想到二分答案mid,因为如果在mid时刻能抓到以后也一直是抓到的。在mid时刻,人可能到达的位置是一个正方形,每个木乃伊能到达的位置也是正方形,我们可以发现如果在mid时刻被抓了,当且仅当木乃伊的移动位置将人的移动位置完全覆盖了。所以我们只需要判断若干个矩形的并是否能覆盖给定矩形即可,用扫描线+线段树可以实现。

但是本人从来没写过矩形并啊,这里学习一发:

考虑标记永久化,我们对于线段树上的每个节点维护cnt:区间中被覆盖的位置个数,sum:当前区间被覆盖了几层。其中cnt相当于值,可以pushup,而sum相当于标记,但不能pushdown。如果一个区间的sum>0,我们令cnt=r-l+1;否则cnt=cnt[lson]+cnt[rson]。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=100010;
int n,tot;
struct node
{
	int l,r,x,k;
	node() {}
	node(int a,int b,int c,int d) {l=a,r=b,x=c,k=d;}
}p[maxn<<1];
int x[maxn],y[maxn],s1[maxn*80],s[maxn*80];
bool tc[maxn*80];
bool cmp(const node &a,const node &b)
{
	return a.x<b.x;
}
void updata(int l,int r,int x,int a,int b,int c)
{
	if(l!=r&&tc[x])	tc[lson]=tc[rson]=1,s1[lson]=s1[rson]=s[lson]=s[rson]=tc[x]=0;
	if(a<=l&&r<=b)
	{
		s[x]+=c;
		if(s[x])	s1[x]=r-l+1;
		else	if(l!=r)	s1[x]=s1[lson]+s1[rson];
		else	s1[x]=0;
		return ;
	}
	int mid=(l+r)>>1;
	if(a<=mid)	updata(l,mid,lson,a,b,c);
	if(b>mid)	updata(mid+1,r,rson,a,b,c);
	if(s[x])	s1[x]=r-l+1;
	else	if(l!=r)	s1[x]=s1[lson]+s1[rson];
	else	s1[x]=0;
}
inline bool check(int mid)
{
	int i;
	tot=0;
	for(i=1;i<=n;i++)
	{
		if(x[i]+mid<-mid||x[i]-mid>mid||y[i]+mid<-mid||y[i]-mid>mid)	continue;
		p[++tot]=node(max(-mid,y[i]-mid),min(mid,y[i]+mid),max(-mid,x[i]-mid),1);
		p[++tot]=node(max(-mid,y[i]-mid),min(mid,y[i]+mid),min(mid+1,x[i]+mid+1),-1);
	}
	sort(p+1,p+tot+1,cmp);
	tc[1]=1,s[1]=s1[1]=0;
	p[0].x=-mid,p[tot+1]=node(0,0,mid+1,0);
	for(i=1;i<=tot+1;i++)
	{
		if(p[i].x>p[i-1].x&&s1[1]<2*mid+1)	return 1;
		updata(-mid,mid,1,p[i].l,p[i].r,p[i].k);
	}
	return 0;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
int main()
{
	for(int cas=1;;cas++)
	{
		n=rd();
		if(n==-1)	return 0;
		int i,l=0,r=1000001,mid;
		for(i=1;i<=n;i++)	x[i]=rd(),y[i]=rd();
		while(l<r)
		{
			mid=(l+r)>>1;
			if(check(mid))	l=mid+1;
			else	r=mid;
		}
		printf("Case %d: ",cas);
		if(l==1000001)	printf("never\n");
		else	printf("%d\n",l);
	}
}//4 -3 5 3 4 -6 -2 1 -5 1 0 -1 -1

 

posted @ 2017-11-26 12:01  CQzhangyu  阅读(467)  评论(0编辑  收藏  举报