洛谷 P2824 [HEOI2016/TJOI2016]排序 线段树

题目描述

在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 ,否则看做 0 。每次排序相当于先询问区间中的 1 的个数,然后进行区间覆盖,直接线段树解决即可。

代码:

#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);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/81834972