qzezoj 1687 Best Cow Fences
题面传送门
我们可以二分这个值。
然后验证时将所有数字减去这个值,看看有没有长度大于\(m\)权值之和大于\(0\)的子段就好了。
代码实现:
#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);
}

浙公网安备 33010602011771号