版权声明:本文为博主原创文章,可以转载但是必须声明版权。 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说明大了。最后复杂度
代码:
#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;
}