【BZOJ】4552: [Tjoi2016&Heoi2016]排序-二分&線段樹
阿新 • • 發佈:2019-01-03
傳送門:bzoj4552
題解
二分答案 ,如何判斷 位置上的數是否大於 呢?
與排序和數值大小有關的問題常用的套路就是把 的數看作1, 的數看作0。本題依次套路將操作轉成了區間求和&賦值。
複雜度
程式碼
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define lc k<<1
#define rc k<<1|1
using namespace std;
const int N=1e5+10;
int n,m,ini[N],ans,l,r,pos,a[N];
int ss[N<<2],st[N<<2];
struct qr{int op,l,r;}q[N];
void build(int k,int l,int r)
{
st[k]=-1;if(l==r) {ss[k]=a[l];return;}
build(lc,l,mid);build(rc,mid+1,r);
ss[k]=ss[lc]+ss[rc];
}
inline void pushdown(int k,int l,int r)
{
if(st[k]==-1) return;
st[lc]=st[rc]=st[k];
ss[lc]=(mid-l+1)*st[k];ss[rc]=(r-mid)*st[k];
st[k]=-1;
}
int ask(int k,int l,int r,int L,int R)
{
if(L<=l && r<=R) return ss[k];
pushdown(k,l,r);
if(R<=mid) return ask(lc,l,mid,L,R);
if(L>mid) return ask(rc,mid+1,r,L,R);
return ask(lc,l,mid,L,R)+ask(rc,mid+1,r,L,R);
}
void dn(int k,int l,int r)
{
if(l==r) {a[l]=ss[k];return;}
pushdown(k,l,r);dn(lc,l,mid);dn(rc,mid+1,r);
}
void cg(int k,int l,int r,int L,int R,int vv)
{
if(L>R) return;
if(L<=l && r<=R) {st[k]=vv;ss[k]=(r-l+1)*vv;return;}
pushdown(k,l,r);
if(L<=mid) cg(lc,l,mid,L,R,vv);
if(R>mid) cg(rc,mid+1,r,L,R,vv);
ss[k]=ss[lc]+ss[rc];
}
inline bool ck(int x)
{
int i,j,l,r;
for(i=1;i<=n;++i) a[i]=(ini[i]>=x);
build(1,1,n);
for(i=1;i<=m;++i){
l=q[i].l;r=q[i].r;
j=ask(1,1,n,l,r);
if(!q[i].op) cg(1,1,n,l,r-j,0),cg(1,1,n,r-j+1,r,1);
else cg(1,1,n,l,l+j-1,1),cg(1,1,n,l+j,r,0);
}
dn(1,1,n);
return a[pos]==1;
}
int main(){
int i,j,l,r;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i) scanf("%d",&ini[i]);
for(i=1;i<=m;++i) scanf("%d%d%d",&q[i].op,&q[i].l,&q[i].r);
scanf("%d",&pos);
for(l=1,r=n;l<=r;) ck(mid)?l=(ans=mid)+1:r=mid-1;
printf("%d",ans);
return 0;
}