zoukankan      html  css  js  c++  java
  • BZOJ 3958 Mummy Madness

    Problem

    BZOJ

    Solution

    算法:二分+扫描线

    快要2019年了,就瞎写一篇博客来凑数,不然感觉太荒凉了……

    答案是可二分的,那么二分的依据是什么呢?不妨设当前二分的答案为\(mid\),那么考虑自己和木乃伊在\(mid\)的时间内能够到达的所有格子,组成了一个正方形,如果自己的正方形被木乃伊的正方形完全覆盖住了,则自己无处可逃。

    那难道就没有可能自己在中途被木乃伊抓住吗?不妨考虑逆推。

    首先我们可以认同的是如果一个格子在\(mid\)时安全,那么它的八联通格子在\(mid-1\)的时间都安全。那么在\(mid\)时对于某个安全格子,它的八联通格子在\(mid-1\)时都是可以落脚的,而且这个格子还要能在\(mid-1\)时到达,这个格子必然存在。那么我们通过不断逆推,即可找到走过来的安全路径。

    时间复杂度\(O(n\log^2 n)\)

    关于细节实现上要多做一点优化,免得TLE。

    Code

    #include <algorithm>
    #include <cstdio>
    #define pushup(rt) sum[rt]=(cnt[rt]?(r-l+1):(sum[rt<<1]+sum[rt<<1|1]))
    using namespace std;
    typedef long long ll;
    const int maxn=4000010;
    template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
    template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
    template <typename Tp> inline void read(Tp &x)
    {
        x=0;int f=0;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=1,ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        if(f) x=-x;
    }
    struct vec{
    	int x,y;
    	bool operator < (const vec &b)const{return x<b.x;}
    }p[maxn];
    int z,n,m,MX,sum[maxn<<2],cnt[maxn<<2];
    int abs(int x){return x<0?-x:x;}
    void update(int l,int r,int L,int R,int val,int rt)
    {
    	if(L<=l&&r<=R){cnt[rt]+=val;pushup(rt);return ;}
    	int m=(l+r)>>1;
    	if(L<=m) update(l,m,L,R,val,rt<<1);
    	if(m<R) update(m+1,r,L,R,val,rt<<1|1);
    	pushup(rt);
    }
    int query(int l,int r,int L,int R,int rt)
    {
    	if(cnt[rt]) return min(R,r)-max(L,l)+1;
    	if(L<=l&&r<=R) return sum[rt];
    	int m=(l+r)>>1,res=0;
    	if(L<=m) res+=query(l,m,L,R,rt<<1);
    	if(m<R) res+=query(m+1,r,L,R,rt<<1|1);
    	return res;
    }
    int cross(int id,int dis)
    {
    	if(p[id].y-dis>dis||p[id].y+dis<-dis) return 0;
    	return 1;
    }
    int check(int x)
    {
    	int s=1,t,res=0,lst=0;
    	while(p[s].x+x<-x) s++;t=s;
    	for(int i=-x;i<=x;i++)
    	{
    		while(s<=n&&p[s].x-x<=i)
    		{
    			if(cross(s,x))
    			{
    				lst=-1;
    				update(-MX,MX,p[s].y-x,p[s].y+x,1,1);
    			}
    			++s;
    		}
    		while(t<=n&&p[t].x+x<i)
    		{
    			if(cross(t,x))
    			{
    				lst=-1;
    				update(-MX,MX,p[t].y-x,p[t].y+x,-1,1);
    			}
    			++t;
    		}
    		if(~lst) continue;
    		lst=query(-MX,MX,-x,x,1);
    		if(lst<(x<<1|1)){res=1;break;}
    	}
    	while(t<s)
    	{
    		if(cross(t,x)) update(-MX,MX,p[t].y-x,p[t].y+x,-1,1);
    		++t;
    	}
    	return res;
    }
    int input()
    {
    	read(n);
    	if(n==-1) return 0;
    	int res=0;MX=0;
    	for(int i=1;i<=n;i++)
    	{
    		read(p[i].x);read(p[i].y);
    		getmax(MX,abs(p[i].y));
    		getmax(res,abs(p[i].x));
    	}
    	getmax(res,MX);MX+=res;
    	sort(p+1,p+n+1);
    	return res;
    }
    int main()
    {
    	int L,R,mid,ans;
    	while((R=input())||(~n))
    	{
    		L=1;ans=-1;
    		while(L<=R)
    		{
    			mid=(L+R)>>1;
    			if(!check(mid)) R=mid-1,ans=mid;
    			else L=mid+1;
    		}
    		if(~ans) printf("Case %d: %d\n",++z,ans);
    		else printf("Case %d: never\n",++z);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Android(java)学习笔记197:ContentProvider使用之内容观察者02
    数据库连接池--druid
    在java中导出excel
    对excel进行封装
    创建excel,合并单元格,设置单元格样式
    认识Excel并创建一个excel(网址:http://poi.apache.org/)
    认识单元测试(jar包资源网址:http://search.maven.org/)
    Echarts在java中使用
    认识Echarts(网址:http://echarts.baidu.com/tutorial.html#ECharts%20%E7%89%B9%E6%80%A7%E4%BB%8B%E7%BB%8D)
    制作缩略图
  • 原文地址:https://www.cnblogs.com/totorato/p/10200448.html
Copyright © 2011-2022 走看看