bzoj 3958: [WF2011]Mummy Madness (扫描线+线段树)

题目描述

传送门

题解

二分一个移动的时间。然后每个木乃伊和自己能到达的区域是一个正方形。
判断自己能到达的区域是否完全被木乃伊所能到达的区域覆盖即可。
有些细节需要注意:
(1) 离散化的时候要插入中间点,否则离散完了不相邻的点都相邻了。
(2) 线段树区间修改的时候不下放标记,对于一个区间如果标记>0,那么答案就是区间的长度,这样子标记都被保留了,删除的时候可以直接删。
(3)需要注意自己能到达的边界,离散的时候要加入-mid,mid。
(4)这道题因为会做很多次,每次清数组会很慢,所以可以打lazy标记。

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define N 400003
using namespace std;
int dx[N],dy[N],cnt,tr[N*4],sum[N*4],lazy[N*4],n;
struct data{
    int opt,val,x,l,r;
}q[N];
struct node{
    int x,y;
}a[N];
void update(int now,int l,int r)
{
    if (tr[now]>0) sum[now]=r-l+1;
    else sum[now]=sum[now<<1]+sum[now<<1|1];
}
void clear(int now)
{
    tr[now]=sum[now]=0;
    lazy[now]=1;
}
void pushdown(int now)
{
    if (lazy[now]) {
        clear(now<<1); 
        clear(now<<1|1);
        lazy[now]=0;
    }
}
void query(int now,int l,int r,int ll,int rr,int v)
{
    pushdown(now);
    if (ll<=l&&r<=rr) {
        tr[now]+=v; update(now,l,r);
        return;
    }
    int mid=(l+r)/2;
    //pushdown(now);
    if (ll<=mid) query(now<<1,l,mid,ll,rr,v);
    if (rr>mid) query(now<<1|1,mid+1,r,ll,rr,v);
    update(now,l,r);
}
int cmp(data a,data b)
{
    return a.x<b.x||a.x==b.x&&a.opt<b.opt;
}
bool check(int mid)
{
    clear(1);
    int cntx=0,cnty=0; cnt=0;
    for (int i=1;i<=n;i++) {
        if (a[i].x+mid<-mid||a[i].y+mid<-mid) continue;
        if (a[i].x-mid>mid||a[i].y-mid>mid) continue;
        ++cnt; q[cnt].x=max(a[i].x-mid,-mid); q[cnt].l=max(a[i].y-mid,-mid); 
        q[cnt].r=min(a[i].y+mid,mid); q[cnt].val=1; q[cnt].opt=1;
        dx[++cntx]=q[cnt].x; dy[++cnty]=q[cnt].l; dy[++cnty]=q[cnt].r;
        ++cnt; q[cnt].x=min(a[i].x+mid+1,mid+1); q[cnt].l=q[cnt-1].l; q[cnt].r=q[cnt-1].r; q[cnt].val=-1; q[cnt].opt=1;
        dx[++cntx]=q[cnt].x; dy[++cnty]=max(q[cnt].l-1,-mid); dy[++cnty]=min(q[cnt].r+1,mid);
    }
    ++cnt; q[cnt].x=-mid; q[cnt].l=-mid; q[cnt].r=mid; q[cnt].opt=2;
    ++cnt; q[cnt].x=mid; q[cnt].l=-mid; q[cnt].r=mid; q[cnt].opt=2;
    dx[++cntx]=-mid; dx[++cntx]=mid; dy[++cnty]=-mid; dy[++cnty]=mid;
    sort(dx+1,dx+cntx+1); sort(dy+1,dy+cnty+1);
    cntx=unique(dx+1,dx+cntx+1)-dx-1;
    cnty=unique(dy+1,dy+cnty+1)-dy-1;
    for (int i=1;i<=cnt;i++)
     q[i].x=lower_bound(dx+1,dx+cntx+1,q[i].x)-dx,
     q[i].l=lower_bound(dy+1,dy+cnty+1,q[i].l)-dy,
     q[i].r=lower_bound(dy+1,dy+cnty+1,q[i].r)-dy;
    int l=1; sort(q+1,q+cnt+1,cmp);
    int t=lower_bound(dx+1,dx+cntx+1,mid)-dx;
    for (int i=1;i<=t;i++) {
        while (q[l].x<=i&&l<=cnt) {
            if (q[l].opt==1) query(1,1,cnty,q[l].l,q[l].r,q[l].val);
            l++;
        }
        if (sum[1]!=cnty) return false;
    }
    return true;
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("my.out","w",stdout);
    int T=0;
    while (true) {
        scanf("%d",&n); T++;
        if (n==-1) break;
        int mx=0,mn=0;
        for (int i=1;i<=n;i++) {
         scanf("%d%d",&a[i].x,&a[i].y);
         mx=max(mx,a[i].x); mx=max(mx,a[i].y);
         mn=min(mn,a[i].x); mn=min(mn,a[i].y);
        }
        int l=1; int r=min(1000000,mx-mn+1); int ans=1000001;
        while (l<=r) {
            int mid=(l+r)/2;
            if (check(mid)) ans=min(ans,mid),r=mid-1;
            else l=mid+1;
        }
        if (ans==1000001) printf("Case %d: never\n",T);
        else printf("Case %d: %d\n",T,ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值