【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;
}
上一篇:CEOI2014 day1 task3 Question


下一篇:uni-app上使用leaflet地图的解决方案