第12届蓝桥杯省赛 C/C++B组 I题.双向排序 题解(线段树)

题意:

一个长度为 n n n的数组 a a a,满足 a [ i ] = i ( 1 ≤ i ≤ n ) a[i]=i (1 \leq i \leq n) a[i]=i(1in) 。有 m m m次操作,分为两种:

1. 1. 1. 对区间 [ 1 , x ] [1,x] [1,x] 进行降序排序

2. 2. 2. 对区间 [ x , n ] [x,n] [x,n] 进行升序排序

输出最后的数组 a a a

( 1 ≤ n , m ≤ 100000 ) ( 1 \leq n,m \leq 100000) (1n,m100000)

题解:

s o r t sort sort只能拿一点分。根据数据范围,可猜得每次操作只能是 l o g log log级别的复杂度。

不难发现,其实数组会被分为两段,前一段是降序的,后一段是升序的。那么可以先维护这个转折点 p p p

假如降序操作的位置小于 p p p,就没必要操作了,升序操作的位置大于等于 p p p,也可以不用操作。

那么如果操作改变了当前数组呢?

我们把在降序部分的数设为 0 0 0,在升序部分的数设为 1 1 1

1. 1. 1.如果降序操作把一部分升序的数变到了降序区,其实就是把为 1 1 1 的数中较小的那几个数变为0。

2. 2. 2. 如果升序操作把一部分降序的数变到了升序区,其实就是把为 0 0 0 的数中较小的那几个数变为1。

这么一看,其实就是修改操作,那么不就是线段树区间修改吗?

最后就能知道哪些数在降序区,哪些数在升序区,那就把降序的数降序排序,升序的数升序排序,最后输出即可。

复杂度就是 O ( m l o g n ) O(mlogn) O(mlogn)

代码:

#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=2e5+5;
const int inf=0x3f3f3f3f;
std::vector<int> v[2];
struct node
{
    int l,r;
    int sum;
    int lazy;
}node[MAXN<<1];
void push_up(int num)
{
    node[num].sum=node[num<<1].sum+node[num<<1|1].sum;
}
void push_down(int num)
{
    if(node[num].lazy==-1) return;
    node[num<<1].lazy=node[num<<1|1].lazy=node[num].lazy;
    node[num<<1].sum=(node[num<<1].r-node[num<<1].l+1)*node[num].lazy;
    node[num<<1|1].sum=(node[num<<1|1].r-node[num<<1|1].l+1)*node[num].lazy;
    node[num].lazy=-1;
}
void build(int l,int r,int num)
{
    node[num].l=l;
    node[num].r=r;
    node[num].lazy=-1;
    if(l==r)
    {
        node[num].sum=1;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
    push_up(num);
}
void updata1(int val,int num)//改为1
{
    int cnt=node[num].r-node[num].l+1-node[num].sum;
    if(cnt<=val)
    {
        node[num].sum=node[num].r-node[num].l+1;
        node[num].lazy=1;
        return;
    }
    push_down(num);
    int mid=(node[num].l+node[num].r)>>1;
    int cnt1=node[num<<1].r-node[num<<1].l+1-node[num<<1].sum;
    int cnt2=node[num<<1|1].r-node[num<<1|1].l+1-node[num<<1|1].sum;
    if(cnt1>=val)
    {
        updata1(val,num<<1);
    }
    else 
    {
        updata1(cnt1,num<<1);
        updata1(val-cnt1,num<<1|1);
    }
    push_up(num);
}
void updata2(int val,int num) //改为0
{
    int cnt=node[num].sum;
    if(cnt<=val)
    {
        node[num].sum=0;
        node[num].lazy=0;
        return;
    }
    push_down(num);
    int mid=(node[num].l+node[num].r)>>1;
    int cnt1=node[num<<1].sum;
    int cnt2=node[num<<1|1].sum;
    if(cnt1>=val)
    {
        updata2(val,num<<1);
    }
    else 
    {
        updata2(cnt1,num<<1);
        updata2(val-cnt1,num<<1|1);
    }
    push_up(num);
}
int query(int pos,int num)
{
    if(node[num].l==node[num].r)
    {
        return node[num].sum;
    }
    push_down(num);
    int mid=(node[num].l+node[num].r)>>1;
    if(pos<=mid)
    {
        return query(pos,num<<1);
    }
    else return query(pos,num<<1|1);
}
int main()
{
    int n,m;
    cin>>n>>m;
    build(1,n,1);
    int pre=1;
    while(m--)
    {
        int op,x;
        cin>>op>>x;
        if(op==1)
        {
            if(x>=pre) continue;
            updata1(pre-x,1);
            pre=x;
        }
        else 
        {
            if(x<pre) continue;
            updata2(x-pre+1,1);
            pre=x+1;
        }
    }
    for(int i=1;i<=n;i++)
    {
        int ans=query(i,1);
        if(ans==0) v[0].push_back(i);
        else v[1].push_back(i);
    }
    for(int i=v[0].size()-1;i>=0;i--)
    {
        cout<<v[0][i]<<" ";
    }
    for(auto i:v[1])
    {
        cout<<i<<" ";
    }

}

posted @ 2021-04-19 17:05  TheBestQAQ  阅读(922)  评论(0)    收藏  举报