C38 线段树+二分 P2824 [HEOI2016/TJOI2016] 排序

视频链接:224 线段树+二分 [HEOI2016TJOI2016] 排序_哔哩哔哩_bilibili

 

 

 

 

Luogu P2824 [HEOI2016/TJOI2016] 排序

// 线段树+二分 nlognlogn
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=100010;
#define ls u<<1
#define rs u<<1|1
int n,m,q;
int a[N],op[N],L[N],R[N];
struct tree{ //线段树
  int l,r;
  int sum,tag;
}tr[N<<2];
//sum:区间1的个数
//tag:-1:区间无标记,0/1:区间赋值为0/1

void pushup(int u){ //上传
  tr[u].sum=tr[ls].sum+tr[rs].sum;
}
void pushdown(int u){ //下传
  if(tr[u].tag==-1) return;
  tr[ls].sum=tr[u].tag*(tr[ls].r-tr[ls].l+1);
  tr[rs].sum=tr[u].tag*(tr[rs].r-tr[rs].l+1);
  tr[ls].tag=tr[rs].tag=tr[u].tag;
  tr[u].tag=-1; //清空懒标记
}
void build(int u,int l,int r,int x){ //建树
  tr[u]={l,r,a[l]>=x,-1};
  if(l==r) return;
  int m=l+r>>1;
  build(ls,l,m,x);
  build(rs,m+1,r,x);
  pushup(u);
}
void change(int u,int x,int y,int k){ //区修
  if(x>tr[u].r || y<tr[u].l) return;
  if(x<=tr[u].l && tr[u].r<=y){
    tr[u].sum=k*(tr[u].r-tr[u].l+1);
    tr[u].tag=k;
    return;
  }
  pushdown(u);
  change(ls,x,y,k);
  change(rs,x,y,k);
  pushup(u);
}
int query(int u,int x,int y){ //区查
  if(x>tr[u].r || y<tr[u].l) return 0;
  if(x<=tr[u].l&&tr[u].r<=y) return tr[u].sum;
  pushdown(u);
  return query(ls,x,y)+query(rs,x,y);
}
bool check(int x){
  build(1,1,n,x);
  for(int i=1; i<=m; i++){
    int l=L[i],r=R[i];
    int cnt=query(1,l,r); //1的个数
    if(op[i]==0){
      change(1,r-cnt+1,r,1);
      change(1,l,r-cnt,0);
    }
    else{
      change(1,l,l+cnt-1,1);
      change(1,l+cnt,r,0);
    }
  }
  return query(1,q,q); //q位置的数
}
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",&op[i],&L[i],&R[i]);
  scanf("%d",&q);
  
  int l=0,r=n+1; //二分答案
  while(l+1<r){
    int mid=l+r>>1;
    check(mid)?l=mid:r=mid;
  }
  printf("%d\n",l);
  return 0;
}

 

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=100010;
#define ls u<<1
#define rs u<<1|1
#define mid (l+r)/2
int n,m,q;
int a[N],op[N],L[N],R[N];
int sum[4*N],tag[4*N];

void pushup(int u){
  sum[u]=sum[ls]+sum[rs];
}
void pushdown(int u,int l,int r){
  if(tag[u]==-1) return;
  sum[ls]=tag[u]*(mid-l+1);
  sum[rs]=tag[u]*(r-mid);
  tag[ls]=tag[rs]=tag[u];
  tag[u]=-1;
}
void build(int u,int l,int r,int x){
  sum[u]=a[l]>=x; tag[u]=-1;  
  if(l==r) return;
  build(ls,l,mid,x); 
  build(rs,mid+1,r,x);
  pushup(u);
}
void change(int u,int l,int r,int x,int y,int k){
  if(x>r || y<l) return;
  if(x<=l && r<=y){
    sum[u]=k*(r-l+1);
    tag[u]=k;
    return;
  }
  pushdown(u,l,r);
  change(ls,l,mid,x,y,k);
  change(rs,mid+1,r,x,y,k);
  pushup(u);
}
int query(int u,int l,int r,int x,int y){
  if(x>r || y<l) return 0;  
  if(x<=l && r<=y) return sum[u];
  pushdown(u,l,r);
  return query(ls,l,mid,x,y)+query(rs,mid+1,r,x,y);
}
bool check(int x){
  build(1,1,n,x);
  for(int i=1; i<=m; i++){
    int l=L[i],r=R[i];
    int cnt=query(1,1,n,l,r);
    if(op[i]==0){
      change(1,1,n,l,r-cnt,0);
      change(1,1,n,r-cnt+1,r,1);
    }
    else{
      change(1,1,n,l+cnt,r,0);
      change(1,1,n,l,l+cnt-1,1);
    }
  }
  return query(1,1,n,q,q);
}
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",&op[i],&L[i],&R[i]);
  scanf("%d",&q);
  
  int l=0,r=n+1;
  while(l+1<r){
    check(mid)?l=mid:r=mid;
  }
  printf("%d\n",l);
  return 0;
}

 

posted @ 2023-09-25 15:50  董晓  阅读(189)  评论(0编辑  收藏  举报