[bzoj4552]排序
听说线段树合并nlogn来着。。。
考虑二分答案,将小于等于mid的数设为0,大于mid的设为1,于是可以nlogn模拟判定(没算二分的)
- 代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N],n,m,P;
int opt[N],l[N],r[N];
struct segtree{
int s[N*8],lzy[N*8];
inline void pushdown(int x,int l,int r){
if(lzy[x]==-1)return;
s[x]=(r-l+1)*lzy[x];
if(l!=r)lzy[x<<1]=lzy[x<<1|1]=lzy[x];
lzy[x]=-1;
}
inline void pushup(int x,int l,int r){
int mid=(l+r)>>1,lch=x<<1,rch=x<<1|1;
if(l==r)return;
pushdown(lch,l,mid);pushdown(rch,mid+1,r);
lzy[x]=-1,s[x]=s[lch]+s[rch];
}
inline void build(int x,int l,int r,int sum){
int mid=(l+r)>>1,lch=x<<1,rch=x<<1|1;
lzy[x]=-1;
if(l==r){
s[x]=sum>=a[l]?0:1;
return;
}
build(lch,l,mid,sum);build(rch,mid+1,r,sum);
s[x]=s[lch]+s[rch];
}
inline void give(int x,int l,int r,int lx,int rx,int sum){
int mid=(l+r)>>1,lch=x<<1,rch=x<<1|1;
if(lx<=l&&r<=rx){
lzy[x]=sum;
return;
}
pushdown(x,l,r);
if(lx<=mid)give(lch,l,mid,lx,rx,sum);
if(rx>mid)give(rch,mid+1,r,lx,rx,sum);
pushup(x,l,r);
}
inline int sum(int x,int l,int r,int lx,int rx){
int mid=(l+r)>>1,lch=x<<1,rch=x<<1|1;
pushdown(x,l,r);
if(lx<=l&&rx>=r){
return s[x];
}
if(rx<=mid)return sum(lch,l,mid,lx,rx);
else if(lx>mid)return sum(rch,mid+1,r,lx,rx);
return sum(lch,l,mid,lx,rx)+sum(rch,mid+1,r,lx,rx);
}
}T;
inline bool chk(int s){
T.build(1,1,n,s);
for(int p=1;p<=m;p++){
int o=opt[p],ql=l[p],qr=r[p];
if(ql>qr)swap(ql,qr);
int al=qr-ql+1;
int one=T.sum(1,1,n,ql,qr);
int zero=al-one;
if(o==0){
if(zero!=0)T.give(1,1,n,ql,ql+zero-1,0);
if(one!=0)T.give(1,1,n,qr-one+1,qr,1);
} else {
if(one!=0)T.give(1,1,n,ql,ql+one-1,1);
if(zero!=0)T.give(1,1,n,qr-zero+1,qr,0);
}
}
int numb=T.sum(1,1,n,P,P);
if(numb==1)return false;
else return true;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)scanf("%d%d%d",&opt[i],&l[i],&r[i]);
scanf("%d",&P);
int l=1,r=n;
while(l<r){
int mid=(l+r)>>1;
bool res=chk(mid);
if(res)r=mid;
else l=mid+1;
}
printf("%d\n",l);
}