【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