听说是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); }