bzoj 3958: [WF2011]Mummy Madness (扫描线+线段树)
2017-04-25 08:49
330 查看
题目描述
传送门
题解
二分一个移动的时间。然后每个木乃伊和自己能到达的区域是一个正方形。判断自己能到达的区域是否完全被木乃伊所能到达的区域覆盖即可。
有些细节需要注意:
(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 ,dy ,cnt,tr[N*4],sum[N*4],lazy[N*4],n; struct data{ int opt,val,x,l,r; }q ; struct node{ int x,y; }a ; 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); } }
相关文章推荐
- 【BZOJ 3958】 3958: [WF2011]Mummy Madness (二分+扫描线、线段树)
- [BZOJ3958][WF2011]Mummy Madness(二分+扫描线+线段树)
- 【BZOJ3958】[WF2011]Mummy Madness 二分+扫描线+线段树
- BZOJ 3958: [WF2011]Mummy Madness
- BZOJ3958: [WF2011]Mummy Madness
- [BZOJ3189][Coci2011][扫描线][线段树]Slika
- [BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】
- 【BZOJ 2333 】[SCOI2011]棘手的操作(离线+线段树|可并堆-左偏树)
- 线段树+扫描线【bzoj1645】[USACO07OPEN]城市的地平线City Horizon
- 【BZOJ4418】[Shoi2013]扇形面积并 扫描线+线段树
- bzoj 2212: [Poi2011]Tree Rotations 线段树合并
- BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
- [bzoj2434][ac自动机][线段树合并][Noi2011]阿狸的打字机
- 【BZOJ3963】[WF2011]MachineWorks cdq分治+斜率优化
- BZOJ 4636: 蒟蒻的数列 线段树/扫描线 set
- ●BZOJ 3963 [WF2011]MachineWorks
- bzoj 1218: [HNOI2003]激光炸弹 (扫描线+线段树)
- 【BZOJ】3963: [WF2011]MachineWorks
- bzoj 2325: [ZJOI2011]道馆之战 (树链剖分+线段树)
- 【BZOJ2243】[SDOI2011]染色【树链剖分】【线段树】