zoukankan      html  css  js  c++  java
  • 【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
    ");
    		else	printf("%d
    ",l);
    	}
    }//4 -3 5 3 4 -6 -2 1 -5 1 0 -1 -1
  • 相关阅读:
    python运行提示缺少模块 No module named 'XX'
    shell脚本删除redis集群中的key
    pytest运行后生成测试报告
    python初级(302) 7 列表(排序练习)
    解决一个右下角图标闪烁,点击图标就会弹出游戏网页的流氓广告
    python初级(302) 7 列表(二)冒泡排序
    python初级(302) 7 列表
    python初级(302) 6 对象(五)
    生命游戏(python实现,pygame显示图形)
    python初级(302) 6 对象(四)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7898666.html
Copyright © 2011-2022 走看看