第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(1≤i≤n) 。有 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) (1≤n,m≤100000)
题解:
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<<" ";
}
}

浙公网安备 33010602011771号