bzoj3958 Mummy Madness 二分答案+扫描线

题目分析

在T时刻,每一个木乃伊可能处于的位置,和你可能处于的位置,都是个正方形。如果木乃伊们的正方形将你的正方形完全覆盖,你无处落脚,必定死亡。

而T+1时刻,因为T时刻木乃伊可能在的每个格子的周围8个格子,此时都可能有木乃伊了,所以,不可能在T时刻没有你可以待的地方,T+1时刻就有了。因此,你无可落脚这个状态是单调的,可以二分。

二分答案,求出所有木乃伊的正方形和你的正方形的并(是个矩形),然后扫描线求出这些矩形的面积并,与你的正方形的面积比较,可知此时你能否活着。

代码

离散化太麻烦,我是用了动态开点线段树……

#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
	int q=0,w=1;char ch=' ';
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') w=-1,ch=getchar();
	while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
	return q*w;
}
typedef long long LL;
const int N=100005,M=2000000;
int n,kas,js,SZ,rt;
struct mummy{int x,y;}mu[N];
struct line{int x,l,r,op;}seg[N<<1];
struct node{int ls,rs;LL v,lz;}tr[N*40];

bool cmp(line l1,line l2) {return l1.x<l2.x;}
void up(int x,int s,int t) {
	if(tr[x].lz) tr[x].v=t-s+1;
	else if(s==t) tr[x].v=0;
	else tr[x].v=tr[tr[x].ls].v+tr[tr[x].rs].v;
}
void ins(int l,int r,int s,int t,int &x,LL num) {
	if(!x) x=++SZ,tr[x].v=tr[x].lz=tr[x].ls=tr[x].rs=0;
	if(l<=s&&t<=r) {tr[x].lz+=num,up(x,s,t);return;}
	int mid=(s+t)>>1;
	if(l<=mid) ins(l,r,s,mid,tr[x].ls,num);
	if(mid+1<=r) ins(l,r,mid+1,t,tr[x].rs,num);
	up(x,s,t);
}
int check(int T) {
	js=SZ=rt=0;LL orz=0;
	for(RI i=1;i<=n;++i) {
		int X1=max(-T,mu[i].x-T),X2=min(T,mu[i].x+T);
		int Y1=max(-T,mu[i].y-T),Y2=min(T,mu[i].y+T);
		if(X1>X2||Y1>Y2) continue;
		seg[++js]=(line){X1,Y1,Y2,1},seg[++js]=(line){X2+1,Y1,Y2,-1};
	}
	sort(seg+1,seg+1+js,cmp);
	for(RI i=1;i<=js;++i) {
		if(i!=1) orz+=1LL*(seg[i].x-seg[i-1].x)*tr[rt].v;
		ins(seg[i].l,seg[i].r,-M,M,rt,seg[i].op);
	}
	return orz>=1LL*(T+T+1)*(T+T+1);
}

int main()
{
	while(1) {
		n=read(),++kas;if(n==-1) break;
		for(RI i=1;i<=n;++i) mu[i].x=read(),mu[i].y=read();
		int l=1,r=1000000,ans=-1;
		while(l<=r) {
			int mid=(l+r)>>1;
			if(check(mid)) ans=mid,r=mid-1;
			else l=mid+1;
		}
		printf("Case %d: ",kas);
		if(ans==-1) puts("never");
		else printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值