P1712 [NOI2016] 区间
我对尺取法并不敏感,所以感觉有点难度,我们想到按照区间长度排序加入使得满足单调性,直到有一个区间的覆盖次数达到了m就可以计算了,而这个就是尺取法,单调性使得我们答案总是最优的。
覆盖次数就可以用线段树做,而且数据范围很大需要离散化,计算答案时注意把答案带回到离散数组中。
我们思路进度:想到可能需要覆盖但不会如何使得区间答案最小化,之后我又以为要线段树记录最大值最小值。
最小化最大最小值使用尺取。
#include <bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1
#define re register
using namespace std;
const int N=5e5+10;
int n,m;
int b[N<<1];
struct ss{
int l,r;
}a[N];
int ans=2e9;
int t[N<<3],add[N<<3];
int getsum(int l,int r){
return (b[a[r].r]-b[a[r].l])-(b[a[l].r]-b[a[l].l]);
}
bool cmp(ss g,ss h){
return (g.r-g.l)<(h.r-h.l);
}
void read(){
cin>>n>>m;
for(re int i=1;i<=n;i++){
cin>>a[i].l>>a[i].r;
b[i*2-1]=a[i].l;
b[i*2]=a[i].r;
}
sort(a+1,a+n+1,cmp);
sort(b+1,b+n*2+1);
int tot=unique(b+1,b+2*n+1)-b-1;
for(re int i=1;i<=n;i++){
a[i].l=lower_bound(b+1,b+1+tot,a[i].l)-b;
a[i].r=lower_bound(b+1,b+1+tot,a[i].r)-b;
}
}
void pushdown(int p,int pl,int pr){
if(add[p]){
int tag=add[p];
add[p]=0;
t[ls]+=tag;
t[rs]+=tag;
add[ls]+=tag;
add[rs]+=tag;
}
}
void change(int p,int pl,int pr,int l,int r,int x){
if(pl>r||pr<l){
return;
}
if(pl>=l&&pr<=r){
t[p]+=x;
add[p]+=x;
return;
}
pushdown(p,pl,pr);
int mid=(pl+pr)>>1;
change(ls,pl,mid,l,r,x);
change(rs,mid+1,pr,l,r,x);
t[p]=max(t[ls],t[rs]);
}
signed main(){
// freopen("P3709_2.in","r",stdin);
// freopen("a.out","w",stdout);
ios::sync_with_stdio(false);
read();
int l=0,r=0;
t[0]=-1;
while(1){
while(t[1]<m&&r<=n){
r++;
change(1,1,2*n,a[r].l,a[r].r,1);
}
if(t[1]<m){
break;
}
while(t[1]>=m&&l<=n){
l++;
change(1,1,2*n,a[l].l,a[l].r,-1);
}
ans=min(ans,getsum(l,r));
}
if(ans==2e9){
cout<<-1;
}
else{
cout<<ans;
}
return 0;
}
标签:pr,int,题解,P1712,NOI2016,ls,区间
From: https://www.cnblogs.com/sadlin/p/18545597