1. 程式人生 > >【BZOJ3958】[WF2011]Mummy Madness 二分+掃描線+線段樹

【BZOJ3958】[WF2011]Mummy Madness 二分+掃描線+線段樹

inpu 試圖 cpp 實現 truct highlight icp 永不 src

【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

【BZOJ3958】[WF2011]Mummy Madness 二分+掃描線+線段樹