zoukankan      html  css  js  c++  java
  • [CF847B] Preparing for Merge Sort

    Description

    给定一个长度为 (n) 的数列 (a_i),每个数互不相同,每轮会从剩余的部分中取出一个下标序列字典序最小的值上升的子序列。按轮输出取出的数列。

    Solution

    先离散化一下

    核心观察是:假如我们在 ([1,i]) 中构建了两个序列,那么结束位置早的那个序列的末尾元素一定比晚的那一个要大

    这个观察提供了可二分性

    我们从左到右扫一遍整个序列,同时用一个 set 维护所有的末尾元素值,每次在末尾元素集合里二分来决定这个元素接在某个的后面还是另开一个

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 1000005;
    
    int n,a[N],b[N],f[N],ind;
    set<int> s;
    map<int,int> mp;
    vector<int> g[N];
    
    signed main() {
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++) mp[a[i]]++;
        for(auto &i:mp) i.second=++ind, b[ind]=i.first;
        for(int i=1;i<=n;i++) a[i]=mp[a[i]];
        for(int i=1;i<=n;i++) {
            auto p=s.lower_bound(a[i]);
            if(p!=s.begin()) {
                --p;
                int x=*p;
                f[a[i]]=x;
                s.erase(p);
            }
            s.insert(a[i]);
        }
        for(int i=1;i<=n;i++) {
            g[f[i]].push_back(i);
        }
        for(int t=1;t<=n;t++) {
            int i=a[t];
            if(f[i]) continue;
            cout<<b[i]<<" ";
            while(g[i].size()) {
                i=g[i][0];
                cout<<b[i]<<" ";
            }
            cout<<endl;
        }
    }
    
  • 相关阅读:
    2021年4月27日 团队冲刺阶段01
    2021年4月26日
    2021年4月25日
    2021年4月24日
    2021年4月23日
    2021年4月22日
    2021年4月21日
    神奇的数列之“Last Defence ”
    经典圆交面积求解之“Intersection ”
    计蒜客第六场
  • 原文地址:https://www.cnblogs.com/mollnn/p/12802039.html
Copyright © 2011-2022 走看看