区间排序(

[Tjoi2016&Heoi2016]排序 - 题目 - 黑暗爆炸OJ

对一个排列进行m次区间内排序操作,给定值q,求位置q上的树

 算法:1.首先由于排列所以值域确定(非排列可以采取离散化处理)对值域二分

 2.将大于m设为1,其余设为0,得到01序列,对每次(细节)check建立一颗线段树

由区间求和可确定区间内的1的个数,从而完成区间内升序降序排列(01序列特性,总和+排序可确定整个序列,求和线段树可以完成,排序为题设要求)

3.为1二分左端点右移(无m)

   为0右端点左移动(包含m)

二分模版!!!

#include<bits/stdc++.h>
using namespace std;
int read() {
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}


const int N=1e5+50;
struct op{
    int type,opl,opr;
}ops[N];
int val[N];
int n,mm,goal,okk=0;
int sum[N<<2],tag[N<<2],bb[N];


void init()
{
  n=read();
  mm=read();
  for(int i=1;i<=n;++i)
  bb[i]=read();
  for(int i=1;i<=mm;++i)
  {
      ops[i].type=read();
      ops[i].opl=read();
      ops[i].opr=read();
  }
  goal=read();
}


void build(int now,int l,int r)
{
 tag[now]=-1;
 if(l==r)
 {
     sum[now]=val[++okk];
     return ;
 }
 int m=(l+r)>>1;
 build(now<<1,l,m);
 build(now<<1|1,m+1,r);
 sum[now]=sum[now<<1]+sum[now<<1|1];
 return ;
}

void pushdown(int now,int l,int r)
{
  int m=(l+r)>>1;
  if(tag[now]!=-1)
  {
      tag[now<<1]=tag[now<<1|1]=tag[now];
      sum[now<<1]=(m-l+1)*tag[now];
      sum[now<<1|1]=(r-m)*tag[now];
  }
  tag[now]=-1;
  return ;
}

void update(int now ,int l,int r,int x,int y,int v)
{
    if(x<=l&&r<=y)
    {
        tag[now]=v;
        sum[now]=v*(r-l+1);
        return ;
    }
    pushdown(now,l,r);
    int m=(l+r)>>1;
    if(x<=m)
    update(now<<1,l,m,x,y,v);
    if(y>m)
    update(now<<1|1,m+1,r,x,y,v);
    sum[now]=sum[now<<1]+sum[now<<1|1];
    return ;
}

int queryy(int now,int l ,int r,int x,int y)
{
    if(x<=l&&r<=y)
    {
        return sum[now];
    }
    pushdown(now,l,r);
    int t1=0,t2=0;
    int m=(l+r)>>1;
    if(x<=m)
    t1=queryy(now<<1,l,m,x,y);
    if(y>m)
    t2=queryy(now<<1|1,m+1,r,x,y);
    sum[now]=sum[now<<1]+sum[now<<1|1];
    return t1+t2;
}

bool check(int x)
{
    int kk;
    for(int i=1;i<=n;++i)
  {
      val[i]=(bb[i]>x)?1:0;
  }
     
     build(1,1,n);
  for(int i=1;i<=mm;++i)
  {
      op aa=ops[i];
    kk=queryy(1,1,n,aa.opl,aa.opr);
    kk=(aa.opr-aa.opl+1)-kk;
    if(aa.type==0)
    {
        if(kk>0)
        {
            update(1,1,n,aa.opl,aa.opl+kk-1,0);
        }
        if(kk<aa.opr-aa.opl+1)
        {
            update(1,1,n,aa.opl+kk,aa.opr,1);
        }
    }
    else {
        if(kk>0)
        {
            update(1,1,n,aa.opr-kk+1,aa.opr,0);
        }
        if(kk<aa.opr-aa.opl+1)
        {
            update(1,1,n,aa.opl,aa.opr-kk,1);
        }
    }
    
  }
    return queryy(1,1,n,goal,goal)==1;
}
int main ()
{
    init();
    int ll=1,rr=n,mid,ans;
    while(ll<rr)
    {
     mid=(ll+rr)>>1;
     if(check(mid))
     {
        ll=mid+1;
     }
     else {
         rr=mid;
     }
        okk=0;
    }
    write(ll);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值