zoukankan      html  css  js  c++  java
  • P4402 [Cerc2007]robotic sort 机械排序 题解

    Description

    Luogu传送门

    Solution

    题目要求我们找到第 \(i\) 的数,其实就维护一下剩下的数中最小值在哪里即可。

    我们考虑使用 \(fhq-treap\)

    说一下具体实现过程:

    • 找到剩下的点中的最小值(其实就是根)。
    • 输出答案,删去它,合并它的两个儿子。
    • 维护区间翻转标记并下传。

    然后就没了。。甚至连 split 都不需要(

    并且维护的这个最小值正好满足小根堆的性质,为了方便,我们可以拿输入的数代替 rand 的值。

    (但是会被卡)

    我们考虑优化建树,使用建笛卡尔树的思想来建树。

    关于笛卡尔树,戳这里

    我们把权值小于当前权值的点挂到当前点的左子树上,再把当前点挂到第一个大于它的点的右子树上,即可构建出一棵相对平衡的平衡树(事实上跑的飞快)。

    这个过程就用单调栈维护一下即可。

    (这样一来反而不如普通的 \(fhq-treap\) 好写了 QwQ)

    还有无关紧要的一点,题目中可能会输入相同的数,如有相同先输出最靠左的,所以稍微处理一下即可,具体见代码。

    Code

    #include <bits/stdc++.h>
    #define ll long long
    #define ls(x) t[x].l
    #define rs(x) t[x].r
    
    using namespace std;
    
    namespace IO{
        inline int read(){
            int x = 0;
            char ch = getchar();
            while(!isdigit(ch)) ch = getchar();
            while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
            return x;
        }
    
        template <typename T> inline void write(T x){
            if(x > 9) write(x / 10);
            putchar(x % 10 + '0');
        }
    }
    using namespace IO;
    
    const int N = 1e5 + 10;
    int n;
    struct fhq_treap{
        int siz, val, l, r;
        ll wei;
        bool rev;
    }t[N];
    int rt, tot;
    
    inline void pushup(int x){
        t[x].siz = t[ls(x)].siz + t[rs(x)].siz + 1;
    }
    
    inline void pushdown(int x){
        if(t[x].rev){
            swap(ls(x), rs(x));
            if(ls(x)) t[ls(x)].rev ^= 1;
            if(rs(x)) t[rs(x)].rev ^= 1;
            t[x].rev = 0;
        }
    }
    
    inline int merge(int x, int y){
        if(!x || !y) return x | y;
        if(t[x].wei <= t[y].wei){
            pushdown(x);
            rs(x) = merge(rs(x), y);
            return pushup(x), x;
        }else{
            pushdown(y);
            ls(y) = merge(x, ls(y));
            return pushup(y), y;
        }
    }
    
    int stk[N], top;
    
    inline void build(int x){
        while(top && t[x].wei < t[stk[top]].wei) ls(x) = stk[top--], pushup(ls(x));
        if(top) rs(stk[top]) = x;
        stk[++top] = x;
    }
    
    inline void update(int x){
        int l = ls(x), r = rs(x);
        ls(x) = rs(x) = 0;
        t[l].rev ^= 1;
        rt = merge(l, r);
    }
    
    signed main(){
        n = read();
        for(int i = 1; i <= n; ++i){
            t[i].wei = 1ll * read() * n + i, t[i].val = i, t[i].siz = 1;
            build(i);
        }
        while(top) pushup(stk[top--]);
        rt = stk[1];
        for(int i = 1; i <= n; ++i){
            pushdown(rt);
            write(t[ls(rt)].siz + i), putchar(' ');
            update(rt);
        }
        return puts(""), 0;
    }
    

    \[\_EOF\_ \]

  • 相关阅读:
    liunx 文件权限注意
    面试必备之乐观锁与悲观锁
    Hibernate之二级缓存
    SELECT INTO 和 INSERT INTO SELECT 两种表复制语句详解(SQL数据库和Oracle数据库的区别)
    ThreadLocal-面试必问深度解析
    Java 8系列之重新认识HashMap(知乎精文)
    Collection接口和Collections类的简单区别和讲解
    细说mysql索引
    【Java面经】非科班渣硕面经
    关于group by的用法 原理(好文章啊,图文并茂,简单易懂)
  • 原文地址:https://www.cnblogs.com/xixike/p/15726570.html
Copyright © 2011-2022 走看看