【2021蓝桥杯省赛】双向排序
3419. 双向排序
给定序列 (a1,a2,⋅⋅⋅,an)=(1,2,⋅⋅⋅,n),即 ai=i。
小蓝将对这个序列进行 m 次操作,每次可能是将 a1,a2,⋅⋅⋅,aqi 降序排列,或者将 aqi,aqi+1,⋅⋅⋅,an 升序排列。
请求出操作完成后的序列。
输入格式
输入的第一行包含两个整数 n,m,分别表示序列的长度和操作次数。
接下来 m 行描述对序列的操作,其中第 i 行包含两个整数 pi,qi 表示操作类型和参数。当 pi=0 时,表示将 a1,a2,⋅⋅⋅,aqi 降序排列;当 pi=1 时,表示将 aqi,aqi+1,⋅⋅⋅,an 升序排列。
输出格式
输出一行,包含 n 个整数,相邻的整数之间使用一个空格分隔,表示操作完成后的序列。
数据范围
对于 30% 的评测用例,n,m≤1000;
对于 60% 的评测用例,n,m≤5000;
对于所有评测用例,1≤n,m≤105,0≤pi≤1,1≤qi≤n。
输入样例:
3 3
0 3
1 2
0 2
输出样例:
3 1 2
样例解释
原数列为 (1,2,3)。
第 1 步后为 (3,2,1)。
第 2 步后为 (3,1,2)。
第 3 步后为 (3,1,2)。与第 2 步操作后相同,因为前两个数已经是降序了。
正解是思维+栈
这里剽窃一下别人的线段树写法:
- 整一个pre做分界点,0修改小于p 1修改大于等于p时候不用修改,跳过。
- 可以发现不论是0修改还是1修改都是修改对立区间最小的几个数‘
- 在线段树上修改除了已有还需要修改的sz个最小的数(也就是在树上左边的区间)
struct SegTree{
int val,lazy;
}segtree[N<<2];
void push_up(int rt){
segtree[rt].val = segtree[rt<<1].val + segtree[rt<<1|1].val;
}
void push_down(int l,int r,int rt){
if(segtree[rt].lazy == -1) return ;
int mid =l+r>>1;
segtree[rt<<1].lazy=segtree[rt<<1|1].lazy = segtree[rt].lazy;
segtree[rt<<1].val = segtree[rt].lazy*(mid-l+1);
segtree[rt<<1|1].val = segtree[rt].lazy*(r-mid);
segtree[rt].lazy = -1;
}
void build(int l,int r,int rt){
segtree[rt].lazy = -1;
if(l == r) { segtree[rt].val = 1; return ; }
int mid =l+r>>1;
build(l,mid,rt<<1); build(mid+1,r,rt<<1|1);
push_up(rt);
}
void update1(int sz,int l,int r,int rt){
int cnt = r-l+1-segtree[rt].val;
if(cnt<=sz) {
segtree[rt].val = r-l+1;
segtree[rt].lazy = 1;
return ;
}
push_down(l,r,rt);
int mid =l+r>>1;
int cnt1 = mid-l+1-segtree[rt<<1].val;
if(cnt1>=sz){
update1(sz,l,mid,rt<<1);
}
else{
update1(cnt1,l,mid,rt<<1);
update1(sz-cnt1,mid+1,r,rt<<1|1);
}
push_up(rt);
}
void update0(int sz,int l,int r,int rt){
int cnt = segtree[rt].val;
if(cnt<=sz) {
segtree[rt].val = 0;
segtree[rt].lazy = 0;
return ;
}
push_down(l,r,rt);
int mid =l+r>>1;
int cnt1 = segtree[rt<<1].val;
if(cnt1>=sz){
update0(sz,l,mid,rt<<1);
}
else{
update0(cnt1,l,mid,rt<<1);
update0(sz-cnt1,mid+1,r,rt<<1|1);
}
push_up(rt);
}
int query(int a,int l,int r,int rt){
if(l==r) return segtree[rt].val;
push_down(l,r,rt);
int mid = l+r>>1;
if(a<=mid) query(a,l,mid,rt<<1);
else query(a,mid+1,r,rt<<1|1);
}
vector<int>ve0; vector<int>ve1;
int main(){
int n,m,opt,x;
cin>>n>>m;
int pre =1;
build(1,n,1);
while(m--){
cin>>opt>>x;
if(opt){//只修改在对立区最小的那几个数
if(x>=pre) continue;
update1(pre-x,1,n,1);
pre= x;
}else{
if(x<pre) continue;
update0(x-pre+1,1,n,1);
pre = x+1;
}
}
for(int i=1;i<=n;i++){if(query(i,1,n,1)) ve1.push_back(i);
else ve0.push_back(i);}
for(int i = ve0.size()-1;i>=0;i--){
cout<<ve0[i]<<" ";
}
for(auto i:ve1){
cout<<i<<" ";
}
cout<<endl;
return 0;
}