题目描述
在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。
这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:
1:(0,l,r)表示将区间[l,r]的数字升序排序
2:(1,l,r)表示将区间[l,r]的数字降序排序
最后询问第q位置上的数字。
输入输出格式
输入格式:
输入数据的第一行为两个整数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
输出格式:
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。
输入输出样例
输入样例#1:
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
输出样例#1:
5
分析:
因为询问只有一个,我们可以先二分一个答案。然后可以把大于等于二分的答案的数看做
1
1
,否则看做。每次排序相当于先询问区间中的
1
1
<script type="math/tex" id="MathJax-Element-53">1</script>的个数,然后进行区间覆盖,直接线段树解决即可。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
const int maxn=1e5+7;
using namespace std;
int n,m,l,r,ans,s;
int a[maxn];
struct node{
int lazy,data;
}t[maxn*4];
struct rec{
int op,l,r;
}q[maxn];
void clean(int p,int l,int r)
{
int mid=(l+r)/2;
if (t[p].lazy!=-1)
{
t[p*2].lazy=t[p].lazy;
t[p*2].data=(mid-l+1)*t[p].lazy;
t[p*2+1].lazy=t[p].lazy;
t[p*2+1].data=(r-mid)*t[p].lazy;
t[p].lazy=-1;
}
}
void ins(int p,int l,int r,int x,int y,int k)
{
if ((l==x) && (r==y))
{
t[p].data=(r-l+1)*k;
t[p].lazy=k;
return;
}
int mid=(l+r)/2;
clean(p,l,r);
if (y<=mid) ins(p*2,l,mid,x,y,k);
else if (x>mid) ins(p*2+1,mid+1,r,x,y,k);
else
{
ins(p*2,l,mid,x,mid,k);
ins(p*2+1,mid+1,r,mid+1,y,k);
}
t[p].data=t[p*2].data+t[p*2+1].data;
}
int count(int p,int l,int r,int x,int y)
{
if ((l==x) && (r==y)) return t[p].data;
int mid=(l+r)/2;
clean(p,l,r);
if (y<=mid) return count(p*2,l,mid,x,y);
else if (x>mid) return count(p*2+1,mid+1,r,x,y);
else return count(p*2,l,mid,x,mid)+count(p*2+1,mid+1,r,mid+1,y);
}
bool check(int c)
{
for (int i=1;i<=n;i++)
{
if (a[i]<c) ins(1,1,n,i,i,0);
else ins(1,1,n,i,i,1);
}
for (int i=1;i<=m;i++)
{
int x=q[i].l,y=q[i].r;
int d=count(1,1,n,x,y);
if (!q[i].op)
{
if (y-d+1<=y) ins(1,1,n,y-d+1,y,1);
if (x<=y-d) ins(1,1,n,x,y-d,0);
}
else
{
if (x<=x+d-1) ins(1,1,n,x,x+d-1,1);
if (x+d<=y) ins(1,1,n,x+d,y,0);
}
}
if (count(1,1,n,s,s)) return true;
return false;
}
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].op,&q[i].l,&q[i].r);
}
scanf("%d",&s);
l=1; r=n;
while (l<=r)
{
int mid=(l+r)/2;
if (check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
printf("%d",ans);
}