bzoj 4552 排序 Posted on 2019-07-04 | Views: 二分 + 线段树. 开始以为是中间有多次询问,想了两节课.读题发现,只在最后询问一次,那就很友好了. 操作/贡献都只与相对大小有关,经典套路就是二分答案,将数列变为 $0/1$ 数列,就可以直接用线段树维护了. 时间复杂度 $O(m\cdot log^2n)$ . 修改操作注意特判 $L>R$ 的情况. 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143#include<bits/stdc++.h>using namespace std;typedef long long ll;inline int read(){ int out=0,fh=1; char jp=getchar(); while ((jp>'9'||jp<'0')&&jp!='-') jp=getchar(); if (jp=='-') fh=-1,jp=getchar(); while (jp>='0'&&jp<='9') out=out*10+jp-'0',jp=getchar(); return out*fh;}const int MAXN=1e5+10;int n,m,q,a[MAXN];struct SegTree{ struct node { int sum,tag; }Tree[MAXN<<2];#define root Tree[o]#define lson Tree[o<<1]#define rson Tree[o<<1|1] void pushup(int o) { root.sum=lson.sum+rson.sum; } void BuildTree(int o,int l,int r,int k) { root.tag=-1; if(l==r) { if(a[l]>=k) root.sum=1; else root.sum=0; return; } int mid=(l+r)>>1; BuildTree(o<<1,l,mid,k); BuildTree(o<<1|1,mid+1,r,k); pushup(o); } void Modifiy(int o,int l,int r,int c) { root.sum=(r-l+1)*c; root.tag=c; } void pushdown(int o,int l,int r) { if(root.tag!=-1) { int mid=(l+r)>>1; Modifiy(o<<1,l,mid,root.tag); Modifiy(o<<1|1,mid+1,r,root.tag); root.tag=-1; } } void upd(int o,int l,int r,int L,int R,int c) { if(L>R) return; if(L<=l && r<=R) { Modifiy(o,l,r,c); return; } pushdown(o,l,r); int mid=(l+r)>>1; if(L<=mid) upd(o<<1,l,mid,L,R,c); if(R>mid) upd(o<<1|1,mid+1,r,L,R,c); pushup(o); } int query(int o,int l,int r,int L,int R) { if(L>R) return 0; if(L<=l && r<=R) return root.sum; pushdown(o,l,r); int mid=(l+r)>>1; int res=0; if(L<=mid) res+=query(o<<1,l,mid,L,R); if(R>mid) res+=query(o<<1|1,mid+1,r,L,R); return res; }}T;struct opt{ int op,L,R;}Q[MAXN];bool check(int k){ T.BuildTree(1,1,n,k); for(int i=1;i<=m;++i) { int L=Q[i].L,R=Q[i].R; int tot1=T.query(1,1,n,L,R); int tot0=R-L+1-tot1; if(Q[i].op==0) { T.upd(1,1,n,L,L+tot0-1,0); T.upd(1,1,n,L+tot0,R,1); } else { T.upd(1,1,n,L,L+tot1-1,1); T.upd(1,1,n,L+tot1,R,0); } } return (bool)(T.query(1,1,n,q,q));}int main(){ n=read(),m=read(); for(int i=1;i<=n;++i) a[i]=read(); for(int i=1;i<=m;++i) { Q[i].op=read(); Q[i].L=read(); Q[i].R=read(); } q=read(); int L=1,R=n,ans=-1; while(L<=R) { int mid=(L+R)>>1; if(check(mid)) ans=mid,L=mid+1; else R=mid-1; } cout<<ans<<endl; return 0;}