听说是BC原题。
好题,二分答案变成01序列,就可以方便的用线段树维护了。
然后就是区间查询和覆盖了。
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define maxn 200005
int cnt[maxn<<2][2],data[maxn],n,m,a[maxn];
int opt[maxn],x[maxn],y[maxn],tag[maxn<<2],q;
void update(int o)
{
F(i,0,1) cnt[o][i]=cnt[o<<1][i]+cnt[o<<1|1][i];
}
void build(int o,int l,int r)
{
if (l==r)
{
cnt[o][data[l]]=1;
cnt[o][1-data[l]]=0;
tag[o]=-1;
return ;
}
tag[o]=-1; int mid=l+r>>1;
build(o<<1,l,mid); build(o<<1|1,mid+1,r);
update(o);
}
void pushdown(int o,int l,int r)
{
if (tag[o]!=-1)
{
int mid=l+r>>1;
tag[o<<1]=tag[o<<1|1]=tag[o];
cnt[o<<1][tag[o]]=mid-l+1;
cnt[o<<1|1][tag[o]]=r-mid;
cnt[o<<1][1-tag[o]]=0;
cnt[o<<1|1][1-tag[o]]=0;
tag[o]=-1;
}
}
int query(int o,int l,int r,int L,int R)
{
if (L<=l&&r<=R) return cnt[o][1];
int mid=l+r>>1; pushdown(o,l,r);
if (R<=mid) return query(o<<1,l,mid,L,R);
else if (L>mid) return query(o<<1|1,mid+1,r,L,R);
else return query(o<<1,l,mid,L,R)+query(o<<1|1,mid+1,r,L,R);
}
void modify(int o,int l,int r,int L,int R,int f)
{
if (L>R) return ;
if (L<=l&&r<=R)
{
tag[o]=f;
cnt[o][f]=r-l+1;
cnt[o][1-f]=0;
return;
}
int mid=l+r>>1; pushdown(o,l,r);
if (L<=mid) modify(o<<1,l,mid,L,R,f);
if (R>mid) modify(o<<1|1,mid+1,r,L,R,f);
update(o);
}
void st_sort(int typ,int l,int r)
{
int cnt1=query(1,1,n,l,r),cnt0=r-l+1-cnt1;
if (typ==0)
{
modify(1,1,n,l,l+cnt0-1,0);
modify(1,1,n,l+cnt0,r,1);
}
else
{
modify(1,1,n,l,l+cnt1-1,1);
modify(1,1,n,l+cnt1,r,0);
}
}
bool check(int mid)
{
F(i,1,n) data[i]=(a[i]>=mid); build(1,1,n);
F(i,1,m)
{
st_sort(opt[i],x[i],y[i]);
}
if (query(1,1,n,q,q)) return true;
else return false;
}
int main()
{
scanf("%d%d",&n,&m);
F(i,1,n) scanf("%d",&a[i]);
F(i,1,m) scanf("%d%d%d",&opt[i],&x[i],&y[i]);
int l=1,r=n;scanf("%d",&q);
while(l<r)
{
int mid=(l+r)/2+1;
if (check(mid)) l=mid;
else r=mid-1;
}
printf("%d
",l);
}