[HEOI2016/TJOI2016]排序
传送门
一个巨佬非常有借鉴意义的思路:
先抛开题目,我们将序列变成01序列,那我们可以怎么做?
很显然,如果[l,r]要降序,那么我们就将[l,l+len-1]标记为1,[l+len,r]标记为0(len表示[l,r]内1的个数),升序同理
这可以用线段树轻易维护
回归题目:
我们考虑二分 询问位置上的数值(设为mid)
我们将所有大于等于mid的数更改为1,小于mid的更改为0
然后按照题目给出的排序,用刚才01序列的排序方法,完完整整做一次排序
那么如果最后在q位置上的数为1,代表
否则
最后就可以二分出一个答案
时间复杂度:O(
常数稍微大点,不过4s还是稳过的
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
using namespace std;
inline int reads()
{
int sign=1,re=0; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') sign=-1; c=getchar();}
while('0'<=c&&c<='9'){re=re*10+(c-'0'); c=getchar();}
return sign*re;
}
int n,m,Q,a[100005];
struct qs
{
int ty,l,r;
}q[100005];
int l,r;
namespace Seg_Tree
{
#define ls (now<<1)
#define rs ((now<<1)|1)
struct Tree
{
int cnt,tag;
}tr[400005];
inline void push_up(int now)
{
tr[now].cnt=tr[ls].cnt+tr[rs].cnt;
}
inline void push_down(int now,int l,int r)
{
int mid=(l+r)>>1;
if(tr[now].tag)
{
tr[ls].tag=tr[rs].tag=tr[now].tag;
if(tr[now].tag==1) tr[ls].cnt=(mid-l+1),tr[rs].cnt=(r-mid);
else tr[ls].cnt=tr[rs].cnt=0;
tr[now].tag=0;
}
}
void buildtree(int now,int l,int r,int num)
{
tr[now].tag=0;
if(l==r)
{
tr[now].cnt=(a[l]>=num);
return;
}
int mid=(l+r)>>1;
buildtree(ls,l,mid,num); buildtree(rs,mid+1,r,num);
push_up(now);
}
void modify(int now,int l,int r,int L,int R,int nw)
{
if(L>R) return;
if(L<=l&&r<=R)
{
(nw==1)?tr[now].cnt=(r-l+1):tr[now].cnt=0;
tr[now].tag=nw;
return;
}
int mid=(l+r)>>1; push_down(now,l,r);
if(L<=mid) modify(ls,l,mid,L,R,nw);
if(mid<R) modify(rs,mid+1,r,L,R,nw);
push_up(now);
}
int query(int now,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tr[now].cnt;
int mid=(l+r)>>1,re=0; push_down(now,l,r);
if(L<=mid) re+=query(ls,l,mid,L,R);
if(mid<R) re+=query(rs,mid+1,r,L,R);
return re;
}
bool point_query(int now,int l,int r)
{
if(l==r) return tr[now].cnt;
int mid=(l+r)>>1; push_down(now,l,r);
if(Q<=mid) return point_query(ls,l,mid);
else point_query(rs,mid+1,r);
}
} using namespace Seg_Tree;
inline bool work(int mid)
{
buildtree(1,1,n,mid);
for(int i=1;i<=m;i++)
{
int cnt=query(1,1,n,q[i].l,q[i].r);
if(q[i].ty)
{
modify(1,1,n,q[i].l,q[i].l+cnt-1,1);
modify(1,1,n,q[i].l+cnt,q[i].r,-1);
}
else
{
modify(1,1,n,q[i].r-cnt+1,q[i].r,1);
modify(1,1,n,q[i].l,q[i].r-cnt,-1);
}
}
return point_query(1,1,n);
}
int main()
{
n=reads(); m=reads();
for(int i=1;i<=n;i++) a[i]=reads();
for(int i=1;i<=m;i++) q[i].ty=reads(),q[i].l=reads(),q[i].r=reads();
Q=reads();
r=n+1;
while(l+1<r)
{
int mid=(l+r)>>1;
if(work(mid)) l=mid;
else r=mid;
}
printf("%d\n",l);
return 0;
}