题解:P11880 [RMI 2024] 选区间 / Choose Interval
豪牛鼻的题。
先考虑个做法,先默认所有操作都是区间加,然后将一个区间加变成补集加,等价于全局
枚举至多做了
令序列最大值为
证明:
先证明下界,因为做一次操作最大值至多
证明上界。
另
定义
考虑证明若
若这
若这
若
于是我们
代码:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define fir first
#define sec second
#define mp make_pair
void chkmin(int &x,int y){x=min(x,y);}
void chkmax(int &x,int y){x=max(x,y);}
const int N=4e5+10,inf=1e9+10;
int n,q,a[N],f[N],t[N],pid[N];
vector<int> H[N];
struct node{int l,r;} Q[N];
void read(){
cin>>q;
n=q*2+1;
for(int i=1;i<=q;i++){
cin>>Q[i].l>>Q[i].r;
H[Q[i].l].push_back(i);
a[Q[i].l]++,a[Q[i].r+1]--;
}
for(int i=1;i<=n;i++) a[i]+=a[i-1];
}
int chk(int m,int V){
V-=m;
for(int i=0;i<=n;i++) t[i]=0;
for(int i=1;i<=q;i++) pid[i]=1;
priority_queue<pii,vector<pii>,less<pii> >q;
while(!q.empty()) q.pop();
int cnt=0,d=0;
for(int i=1;i<=n;i++){
d+=t[i];
for(int p:H[i]){
q.push(mp(Q[p].r,p));
}
while(d+a[i]>V){
if(q.empty() || q.top().fir<i) return 0;
pii p=q.top();
q.pop();
pid[p.sec]=0;
t[p.fir+1]+=2;
d-=2;
cnt++;
if(cnt>m) return 0;
}
}
return 1;
}
void work(){
int Max=0;
for(int i=1;i<=n;i++) chkmax(Max,a[i]);
int L=0,R=q;
while(L<R){
int mid=(L+R)>>1;
if(chk(Max-mid,mid) || chk(Max-mid+1,mid)) R=mid;
else L=mid+1;
}
cout<<L<<'\n';
if(chk(Max-L,L)){
for(int i=1;i<=q;i++) cout<<pid[i];
cout<<'\n';
}else{
chk(Max-L+1,L);
for(int i=1;i<=q;i++) cout<<pid[i];
cout<<'\n';
}
}
int main(){
ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
read();
work();
cerr<<1.0*clock()/CLOCKS_PER_SEC<<'\n';
return 0;
}