• 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
    ",ans);
    	return 0;
    }
    

    深深地感到自己的弱小。

  • 相关阅读:
    Oracle删除用户和表空间
    PLSQL配置教程
    Oracle 11g client 安装
    oracle 11g 安装
    oracle创建用户空间、导出、导入dmp备份文件方法
    c#关键字
    c#运算符重载
    每天一个Linux命令之date
    linux之2>&1
    每天一个Linux命令之crontab
  • 原文地址:https://www.cnblogs.com/syzf2222/p/13982904.html
Copyright © 2020-2023  润新知