Description
在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题
,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排
序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q
位置上的数字。
Input
输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。1 <= n, m <= 10^5第二行为n个整
数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序
排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5
,1 <= m <= 10^5
Output
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。
Sample Input
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
Sample Output
5
思路
二分答案,判断排序之后的A[q]与mid的关系,
先把原序列中大于mid的数标记为1,否则标记为0。
对01序列进行排序,可以通过线段树完成计数排序,
需要实现区间求和、区间赋值。
最后如果A[q]=1,说明原序列中A[q]>mid ,
否则原序列中A[q] mid 。
求最小的mid满足排序后的序列中A[q] = 0。
复杂度O (nlog^2n)。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=200000+5;
int A[N],v[N];
struct data
{
int op,x,y;
}B[N];
int n,M,q,np,rt,cnt[2*N],chi[2*N][2],down[2*N];
void build(int &now,int L,int R)
{
now=++np;cnt[now]=down[now]=0;
chi[now][0]=chi[now][1]=0;
if (L==R) {cnt[now]=v[L];return ;}
int mid=(L+R)>>1;
build(chi[now][0],L,mid);
build(chi[now][1],mid+1,R);
cnt[now]=cnt[chi[now][0]]+cnt[chi[now][1]];
return ;
}
void pushdown(int now,int L,int R)
{
int mid=(L+R)/2;
if (down[now])
{
down[chi[now][0]]=down[chi[now][1]]=down[now];
cnt[chi[now][0]]=(mid-L+1)*(down[now]-1);
cnt[chi[now][1]]=(R-mid)*(down[now]-1);
}
down[now]=0;
return ;
}
void update(int now,int L,int R,int x,int y,int v)
{
if (x<=L&&R<=y) {down[now]=v+1;cnt[now]=v*(R-L+1);return ;}
pushdown(now,L,R);
int mid=(L+R)>>1;
if (x<=mid) update(chi[now][0],L,mid,x,y,v);
if (y>mid) update(chi[now][1],mid+1,R,x,y,v);
cnt[now]=cnt[chi[now][0]]+cnt[chi[now][1]];
return;
}
int query(int now,int L,int R,int x,int y)
{
if (x<=L&&R<=y) return cnt[now];
pushdown(now,L,R);
int mid=(L+R)>>1;
int t1=0,t2=0;
if (x<=mid) t1=query(chi[now][0],L,mid,x,y);
if (y>mid) t2=query(chi[now][1],mid+1,R,x,y);
cnt[now]=cnt[chi[now][0]]+cnt[chi[now][1]];
return t1+t2;
}
bool check(int x)
{
for (int i=1;i<=n;i++)
v[i]=A[i]<=x? 0:1;
np=0;int ct;
build(rt,1,n);
for (int i=1;i<=M;i++)
{
ct=query(rt,1,n,B[i].x,B[i].y);
if (B[i].op==0)
{
ct=B[i].y-B[i].x+1-ct;
if (ct>0) update(rt,1,n,B[i].x,B[i].x+ct-1,0);
if (ct<=B[i].y-B[i].x) update(rt,1,n,B[i].x+ct,B[i].y,1);
}
else
{
if (ct>0) update(rt,1,n,B[i].x,B[i].x+ct-1,1);
if (ct<=B[i].y-B[i].x) update(rt,1,n,B[i].x+ct,B[i].y,0);
}
}
return query(rt,1,n,q,q)==0;
}
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",&B[i].op,&B[i].x,&B[i].y);
scanf("%d",&q);
int l=1,r=n,mid,ans;
while(l<=r)
{
mid=(l+r)>>1;
if (check(mid)) { r=mid-1;ans=mid;}
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}