BZOJ3958: [WF2011]Mummy Madness

41 篇文章 0 订阅

可以发现,你被抓住的时间满足二分性,因为若在时间x你被抓住了,那么对于任意时间y>x,木乃伊都一定能抓住你
那么二分这个时间,你能走到的地方是一个矩形,同时每个木乃伊能走到的地方也是一个矩形,扫描线扫一下,若整个矩形都被覆盖了就会被抓住
(只处理每个木乃伊的矩形和你走到的矩形的交的部分,不然可能会T)
code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c; int f=1;
    while(!((c=getchar())>='0'&&c<='9')) if(c=='-') f=-f;
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0';
    x*=f;
}
inline void up(int &x,const int y){if(x<y)x=y;}
inline int _max(const int &x,const int &y){return x>y?x:y;}
inline int _min(const int &x,const int &y){return x<y?x:y;}
const int maxn = 210000;
const int maxc = 1010000;

int n,C;
struct P{int x,y;}p[maxn];

struct edge
{
    int l,r,c,nex;
    edge(){}
    edge(const int _l,const int _r,const int _c,const int _nex){l=_l;r=_r;c=_c;nex=_nex;}
}a[maxn<<1]; int len,fir[maxc<<1];
inline void ins(const int x,const int l,const int r,const int c)
{
    a[++len]=edge(l,r,c,fir[x]);fir[x]=len;
}

struct segment
{
    int flag,c;
}seg[maxc<<4];
int lx,rx,c;
void upd(const int x,const int l,const int r)
{
    if(lx<=l&&r<=rx) { seg[x].flag+=c; seg[x].c+=c; return; }
    if(rx<l||r<lx) return;
    upd(x<<1,l,l+r>>1),upd((x<<1)|1,(l+r>>1)+1,r);
    seg[x].c=seg[x].flag+_min(seg[x<<1].c,seg[(x<<1)|1].c);
}

bool Judge(const int m)
{
    len=0; for(int i=0;i<=2*C+1;i++) fir[i]=0;

    for(int i=1;i<=n;i++)
    {
        int d=m+max(p[i].y-m,-m),u=m+min(p[i].y+m,m);
        int l=m+max(p[i].x-m,-m),r=m+min(p[i].x+m,m);
        if(u>=0&&d<=u) ins(d,l,r,1),ins(u+1,l,r,-1);
    }

    bool flag=false;
    for(int i=0;i<=2*m;i++)
    {
        for(int k=fir[i];k;k=a[k].nex) 
        {
            lx=a[k].l,rx=a[k].r,c=a[k].c;
            if(lx<=rx) upd(1,0,m<<1);
        }
        if(!seg[1].c) flag=true;
    }
    for(int k=fir[2*m+1];k;k=a[k].nex) 
    {
        lx=a[k].l,rx=a[k].r,c=a[k].c;
        if(lx<=rx) upd(1,0,m<<1);
    }
    return flag;
}
int solve()
{
    int l=1,r=C;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(Judge(mid)) l=mid+1;
        else r=mid-1;
    }
    return l-1;
}

int main()
{
    for(int t=1;scanf("%d",&n)&&n!=-1;t++)
    {
        C=0;
        for(int i=1;i<=n;i++)
        {
            int x,y; read(x); read(y);
            p[i].x=x; p[i].y=y;
            up(C,abs(x)); up(C,abs(y));
        }
        int re=solve()+1;
        printf("Case %d: ",t);
        if(re==C+1) printf("never\n");
        else printf("%d\n",re);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值