洛谷P2824 BZOJ4552[HEOI2016/TJOI2016]排序 二分答案 线段树

版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/82941045

题目链接
题意:
给你一个1-n的全排列,有m次操作,每次把一个区间[l,r]升序排序或者降序排序,最后有1次询问,求m次操作后某一个位置的权值。

题解:
这题做法比较神奇。我们二分最后的答案,这样我们把大于二分的值的数变成1,小于等于的变成0,然后就可以对于每次操作用线段树维护了,维护的方法是记录区间0的个数和1的个数,这样每次区间排序就相当于先询问区间中0的个数和1的个数,然后根据升序和降序的要求,对区间的前面一部分和后面一部分进行区间01覆盖。最后答案的话就是单点查询,我写的是单点查询0的个数,如果是0说明当前的二分值小了,是1说明大了。最后复杂度 n l o g 2 n nlog^2n
代码:

#include <bits/stdc++.h>
using namespace std;

int n,m,a[200010],ans,b[200010],qq;
struct tree
{
 int l,r,s0,s1,tag;
}tr[800010];
struct qwq
{
 int opt,l,r;
}q[200010];
inline void pushup(int rt)
{
 tr[rt].s0=tr[rt<<1].s0+tr[rt<<1|1].s0;
 tr[rt].s1=tr[rt<<1].s1+tr[rt<<1|1].s1;
}
inline void build(int rt,int l,int r)
{
 tr[rt].l=l;
 tr[rt].r=r;
 tr[rt].tag=0;
 if(l==r)
 {
  if(b[l]==0)
  { 
   tr[rt].s0=1;
   tr[rt].s1=0;
  }
  else
  {
   tr[rt].s0=0;
   tr[rt].s1=1;
  }  
  return;
 }
 int mid=(l+r)>>1;
 build(rt<<1,l,mid);
 build(rt<<1|1,mid+1,r);
 pushup(rt);
}
inline void pushdown(int rt)
{
 if(tr[rt].tag)
 {
  tr[rt<<1].tag=tr[rt].tag;
  tr[rt<<1|1].tag=tr[rt].tag;
  if(tr[rt].tag==1)
  {
   tr[rt<<1].s0=tr[rt<<1].r-tr[rt<<1].l+1;
   tr[rt<<1].s1=0;
   tr[rt<<1|1].s0=tr[rt<<1|1].r-tr[rt<<1|1].l+1;
   tr[rt<<1|1].s1=0;
  }
  else
  {
   tr[rt<<1].s0=0;
   tr[rt<<1].s1=tr[rt<<1].r-tr[rt<<1].l+1;
   tr[rt<<1|1].s0=0;
   tr[rt<<1|1].s1=tr[rt<<1|1].r-tr[rt<<1|1].l+1;
  }
  tr[rt].tag=0;
 }
}
inline int query(int rt,int le,int ri)
{
 int l=tr[rt].l,r=tr[rt].r;
 if(le<=l&&r<=ri)
 return tr[rt].s0;
 pushdown(rt);
 int mid=(l+r)>>1,res=0;
 if(le<=mid)
 res+=query(rt<<1,le,ri);
 if(mid+1<=ri)
 res+=query(rt<<1|1,le,ri);
 return res;
}
inline void update(int rt,int le,int ri,int x)
{
 int l=tr[rt].l,r=tr[rt].r;
 if(le<=l&&r<=ri)
 {
  tr[rt].tag=x+1;
  if(x==0)
  {
   tr[rt].s0=r-l+1;
   tr[rt].s1=0;
  }
  else
  {
   tr[rt].s0=0;
   tr[rt].s1=r-l+1;
  }
  return;
 }
 pushdown(rt);
 int mid=(l+r)>>1;
 if(le<=mid)
 update(rt<<1,le,ri,x);
 if(mid+1<=ri)
 update(rt<<1|1,le,ri,x);
 pushup(rt);
}
inline int check(int mid)
{
 for(int i=1;i<=n;++i)
 {
  if(a[i]<=mid)
  b[i]=0;
  else
  b[i]=1;
 }
 build(1,1,n);
 for(int i=1;i<=m;++i)
 {
  if(q[i].opt==0)
  {
   int ji=query(1,q[i].l,q[i].r);
   if(ji);
   update(1,q[i].l,q[i].l+ji-1,0);
   update(1,q[i].l+ji,q[i].r,1);
  }
  else
  {   
   int ji=query(1,q[i].l,q[i].r);
   update(1,q[i].l,q[i].r-ji,1);
   update(1,q[i].r-ji+1,q[i].r,0);
  }
 }
 int ji=query(1,qq,qq);
 if(ji==0)
 return 0;
 else
 return 1;
}
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",&q[i].opt,&q[i].l,&q[i].r);
 scanf("%d",&qq);
 int l=1,r=n,mid;
 while(l<=r) 
 {
  mid=(l+r)>>1;
  if(check(mid))
  {
   ans=mid;
   r=mid-1;
  }
  else
  l=mid+1;
 }
 printf("%d\n",ans);
 return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/82941045