P2862 [USACO06JAN]Corral the Cows G

考虑二分答案,问题转化为能否用边长为\(len\)的正方形框住大于等于\(c\)个草场。

继续转化问题,即边长为\(len\)的正方形能框住的最多草场数是否大于\(c\)

考虑每一个右下角\((x,y)\),则每一个横坐标在\([x-len+1,x]\),纵坐标在\([y,y+len-1]\)中的草场都可以被框住。

转而考虑每一个草场\((x,y)\)的贡献,它对横坐标在\([x,x+len-1]\),纵坐标在\([y-len+1,y]\)的右下角都有贡献。

考虑扫描线,对于每一个草场可以看成两个线段,即\(\{x,y-len+1,y,1\}\)\(\{x+len,y-len+1,y,-1\}\)

即这个草场从\(x\)起在区间\([y-len+1,y]\)上生效,从\(x+len\)起失效。

线段树维护最大值即可,时间复杂度\(\Theta(nlogn)\)(二分+扫描线)。

代码如下,仅供参考:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int maxn=1e4+10;
const int N=1e4+5;
int n,m,ans,a[maxn],b[maxn],tot;
struct node{int pos,l,r,val;}p[maxn];
inline int cmp(node x,node y){
	if(x.pos==y.pos)return x.val<y.val;
	return x.pos<y.pos;
}
int tr[maxn<<4],lazy[maxn<<4];
inline void build(int h,int l,int r){
	tr[h]=lazy[h]=0;
	if(l==r)return;
	int mid=(l+r)>>1;
	build(h<<1,l,mid);
	build(h<<1|1,mid+1,r);
}
inline void pushup(int h,int z){
	tr[h]+=z;lazy[h]+=z;
}
inline void pushdown(int h){
	if(!lazy[h])return;
	pushup(h<<1,lazy[h]);
	pushup(h<<1|1,lazy[h]);
	lazy[h]=0;
}
inline void update(int h,int l,int r,int x,int y,int z){
	if(l>y||r<x)return;
	if(l>=x&&r<=y){pushup(h,z);return;}
	pushdown(h);
	int mid=(l+r)>>1;
	update(h<<1,l,mid,x,y,z);
	update(h<<1|1,mid+1,r,x,y,z);
	tr[h]=max(tr[h<<1],tr[h<<1|1]);
}
inline int check(int len){
	build(1,-N,N);tot=0;
	for(int i=1;i<=n;i++){
		p[++tot]=(node){a[i],b[i]-len+1,b[i],1};
		p[++tot]=(node){a[i]+len,b[i]-len+1,b[i],-1};
	}
	sort(p+1,p+1+tot,cmp);
	for(int i=1;i<=tot;i++){
		update(1,-N,N,p[i].l,p[i].r,p[i].val);
		if(tr[1]>=m)return 1;
	}
	return 0;
}
int main(){
	m=read(),n=read();
	for(int i=1;i<=n;i++)
		a[i]=read(),b[i]=read();
	int l=1,r=N;
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(mid))ans=mid,r=mid-1;
		else l=mid+1;
	}
	printf("%d\n",ans);
	return 0;
}

深深地感到自己的弱小。

posted @ 2020-11-15 22:58  syzf2222  阅读(96)  评论(0编辑  收藏  举报