把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P2862 [USACO06JAN]Corral the Cows G

题面传送门
这东西有一个更优的复杂度。
显然可以二分,二分以后对每一维尺取后算是\(O(nwlogw)\)的,可以过去。
但是我们发现在第二维尺取时的这一维\(w\)很没有必要,换句话说,很没效率。
所以就可以用一棵权值线段树代替掉,对每一个点向后\(mid\)个贡献权值。查询时查询最大值即可。
代码实现:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,l,r,mid,f[80039],sum[80039],ans;
struct yyy{int x,y;}s[10039];
inline bool cmp(yyy x,yyy y){return x.x<y.x;}
inline void push(int now){
	f[now<<1]+=f[now];f[now<<1|1]+=f[now];
	sum[now<<1]+=f[now];sum[now<<1|1]+=f[now];
	f[now]=0;
}
inline void get(int x,int y,int z,int l,int r,int now){
	if(x<=l&&r<=y){f[now]+=z;sum[now]+=z;return;}
	if(f[now]) push(now);
	int m=(l+r)>>1;
	if(x<=m) get(x,y,z,l,m,now<<1);
	if(y>m) get(x,y,z,m+1,r,now<<1|1);
	sum[now]=max(sum[now<<1],sum[now<<1|1]);
}
inline int check(int mid){
	memset(f,0,sizeof(f));memset(sum,0,sizeof(sum));
	register int i,l=1,j;
	for(i=1;i<=n;i++){
		get(s[i].y,min(s[i].y+mid-1,ans),1,1,ans,1);
		if(s[i+1].x!=s[i].x){
			while(s[i].x-s[l].x+1>mid)get(s[l].y,min(s[l].y+mid-1,ans),-1,1,ans,1),l++;
			if(sum[1]>=m) return 1;
		}
	}
	return 0;
}
int main(){
	register int i;
	scanf("%d%d",&m,&n);
	for(i=1;i<=n;i++) scanf("%d%d",&s[i].x,&s[i].y),ans=max(ans,max(s[i].y,s[i].x));
	sort(s+1,s+n+1,cmp);
	l=0;r=ans;
	while(l+1<r){
		mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid;
	}
	printf("%d\n",r);
}
posted @ 2020-08-18 15:58  275307894a  阅读(55)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end