Description
在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:
1:(0,l,r)表示将区间[l,r]的数字升序排序
2:(1,l,r)表示将区间[l,r]的数字降序排序
最后询问第q位置上的数字。
Solution
直接排序暴力?(竟然可以水80分!)
直接操作显然是不可以的。
我们二分答案,把原序列每个 ai 减去每次二分的 mid ,然后若 ai≥mid 则变为1,反之变为0,这样我们得到了一个01序列,这样我们可以用线段树维护每次部分排序,最后判断q位置上的数值来确定下一次的mid值。
复杂度为 O(mlog2n) 。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define N 100001
using namespace std;
int a[N];
int b[N][3];
int c[N];
struct node{
int _0,_1;
int lazy;
}tr[N*4];
int n,m;
int Q;
void build(int v,int l,int r)
{
if(l==r)
{
tr[v]._0=tr[v]._1=0;
if(!c[l]) tr[v]._0=1;
else tr[v]._1=1;
tr[v].lazy=-1;
return;
}
int mid=(l+r)/2;
build(v*2,l,mid);
build(v*2+1,mid+1,r);
tr[v]._0=tr[v*2]._0+tr[v*2+1]._0;
tr[v]._1=tr[v*2]._1+tr[v*2+1]._1;
tr[v].lazy=-1;
}
void put(int v,int l,int r,int mid)
{
if(tr[v].lazy<0) return;
if(tr[v].lazy==0)
{
tr[v*2]._0=mid-l+1,tr[v*2+1]._0=r-mid;
tr[v*2]._1=tr[v*2+1]._1=0;
}
else
{
tr[v*2]._1=mid-l+1,tr[v*2+1]._1=r-mid;
tr[v*2]._0=tr[v*2+1]._0=0;
}
tr[v*2].lazy=tr[v*2+1].lazy=tr[v].lazy;
tr[v].lazy=-1;
}
void change(int v,int l,int r,int x,int y,int t)
{
if(l==x && r==y)
{
tr[v].lazy=t;
if(t==0) tr[v]._0=r-l+1,tr[v]._1=0;
else tr[v]._1=r-l+1,tr[v]._0=0;
return;
}
int mid=(l+r)/2;
put(v,l,r,mid);
if(y<=mid) change(v*2,l,mid,x,y,t);
else if(x>mid) change(v*2+1,mid+1,r,x,y,t);
else
{
change(v*2,l,mid,x,mid,t);
change(v*2+1,mid+1,r,mid+1,y,t);
}
tr[v]._0=tr[v*2]._0+tr[v*2+1]._0;
tr[v]._1=tr[v*2]._1+tr[v*2+1]._1;
}
int find(int v,int l,int r,int x,int y,int t)
{
if(l==x && r==y)
{
if(!t) return tr[v]._0;
else return tr[v]._1;
}
int mid=(l+r)/2;
put(v,l,r,mid);
if(y<=mid) return find(v*2,l,mid,x,y,t);
else if(x>mid) return find(v*2+1,mid+1,r,x,y,t);
else return find(v*2,l,mid,x,mid,t)+find(v*2+1,mid+1,r,mid+1,y,t);
}
int findans(int v,int l,int r,int x)
{
if(l==r && l==x)
{
return tr[v]._0?0:1;
}
int mid=(l+r)/2;
put(v,l,r,mid);
if(x<=mid) return findans(v*2,l,mid,x);
else return findans(v*2+1,mid+1,r,x);
}
bool check(int mid)
{
fo(i,1,n) c[i]=(a[i]>=mid);
build(1,1,n);
fo(i,1,m)
{
int t=b[i][0],x=b[i][1],y=b[i][2];
int q=find(1,1,n,x,y,t);
if(x<=x+q-1) change(1,1,n,x,x+q-1,t);
if(x+q<=y) change(1,1,n,x+q,y,1-t);
}
int z=findans(1,1,n,Q);
if(z) return true;
else return false;
}
int main()
{
freopen("2.in","r",stdin);
freopen("2.out","w",stdout);
cin>>n>>m;
int mmax=0;
fo(i,1,n)
scanf("%d",&a[i]);
fo(i,1,m)
{
int t,l,r;
scanf("%d %d %d",&t,&l,&r);
b[i][0]=t;
b[i][1]=l;
b[i][2]=r;
}
cin>>Q;
int l=1,r=n,ans;
while(l<r)
{
int mid=(l+r)/2;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
if(check(l)) ans=l;
cout<<ans;
}