zoukankan      html  css  js  c++  java
  • 【整体二分】【P3834】 【模板】可持久化线段树 1(主席树)

    Description

    给定一个长度为 (n) 的序列, (m) 次操作静态查询区间第 (k)

    Input

    第一行是 (n,m)

    下一行描述这个序列

    下面 (m) 行描述操作

    Output

    每个查询输出一行一个数代表答案

    Hint

    (1~leq~n,~m~leq~2~ imes~10^5)

    值域为 ([-1e9,~1e9])

    Solution

    考虑整体二分。

    将操作和序列全部离线,混在一起操作,在每层中,如果一个插入操作插入的数大于 mid,则压入右边的vector,否则压入左边的vector,这样即可保证在每一层整个序列的插入操作只被操作 (1) 次。用树状数组维护不大于 mid 的插入点,插入点个数不小于 (k) 的查询压入左侧,否则 (k~-=~ ext{压入点个数}) ,压入右侧即可。

    注意一个区间内没有操作的时候要剪枝,否则复杂度会加上值域。

    总复杂度 (O((n + m)~log^2 m))

    Code

    // luogu-judger-enable-o2
    #include <cstdio>
    #include <vector>
    #include <iostream>
    #ifdef ONLINE_JUDGE
    #define freopen(a, b, c)
    #endif
    
    typedef long long int ll;
    
    namespace IPT {
        const int L = 1000000;
        char buf[L], *front=buf, *end=buf;
        char GetChar() {
            if (front == end) {
                end = buf + fread(front = buf, 1, L, stdin);
                if (front == end) return -1;
            }
            return *(front++);
        }
    }
    
    template <typename T>
    inline void qr(T &x) {
        char ch = IPT::GetChar(), lst = ' ';
        while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
        while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
        if (lst == '-') x = -x;
    }
    
    namespace OPT {
        char buf[120];
    }
    
    template <typename T>
    inline void qw(T x, const char aft, const bool pt) {
        if (x < 0) {x = -x, putchar('-');}
        int top=0;
        do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);
        while (top) putchar(OPT::buf[top--]);
        if (pt) putchar(aft);
    }
    
    const int maxn = 200010;
    const int INF = 1000000010;
    
    struct OP {
        int l, r, k, id;
    };
    std::vector<OP> Q;
    
    int n, m;
    int ans[maxn], tree[maxn];
    
    int lowbit(int);
    int query(int);
    void update(int, const int);
    void divide(int, int, std::vector<OP>&);
    
    int main() {
        freopen("1.in", "r", stdin);
        qr(n); qr(m);
        for (int i = 1, x; i <= n; ++i) {
            x = 0; qr(x); Q.push_back({-1, 0, x, i});
        }
        for (int i = 1, a, b, c; i <= m; ++i) {
            a = b = c = 0; qr(a); qr(b); qr(c);
            Q.push_back({a, b, c, i});
        }
        divide(-INF, INF, Q);
        for (int i = 1; i <= m; ++i) qw(ans[i], '
    ', true);
        return 0;
    }
    
    void divide(int l, int r, std::vector<OP> &v) {
        if (!v.size()) return;
        if (l == r) {
            for (auto i : v) if (i.l != -1) ans[i.id] = l;
            return;
        }
        std::vector<OP>ldown, rdown;
        int mid = (l + r) >> 1;
        for (auto i : v) {
            if (i.l == -1) {
                if (i.k <= mid) {
                    update(i.id, 1);
                    ldown.push_back(i);
                } else rdown.push_back(i);
            }
        }
        for (auto i : v) {
            if (i.l != -1) {
                int k = query(i.r) - query(i.l - 1);
                if ((k) >= i.k) ldown.push_back(i);
                else {
                    i.k -= k; rdown.push_back(i);
                }
            }
        }
        for (auto i : ldown) {
            if (i.l == -1) update(i.id, -1);
        }
        divide(l, mid, ldown);
        divide(mid + 1, r, rdown);
    }
    
    inline int lowbit(int x) {return x & -x;}
    
    void update(int x, const int v) {
        while (x <= n) {
            tree[x] += v;
            x += lowbit(x);
        }
    }
    
    int query(int x) {
        int _ret = 0;
        while (x) {
            _ret += tree[x];
            x -= lowbit(x);
        }
        return _ret;
    }
    
  • 相关阅读:
    TCP ,UDP概念和TCP三次握手连接 的知识点总结
    常见的五类排序算法图解和实现(插入类:直接插入排序,折半插入排序,希尔排序)
    c/c++ 函数、常量、指针和数组的关系梳理
    编译器出现conflicting types for 某某的错误原因总结
    字符串模式匹配之KMP算法图解与 next 数组原理和实现方案
    图解字符串的朴素模式匹配算法
    字符串和字符串的常见存储结构
    objective-c中的@selector()和 c /c++的函数指针
    IOS-Foundation框架结构
    一道面试题:用多种方法实现两个数的交换
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10430542.html
Copyright © 2011-2022 走看看