【整体二分】【P3834】 【模板】可持久化线段树 1(主席树)

Description

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

Input

第一行是 \(n,m\)

下一行描述这个序列

下面 \(m\) 行描述操作

Output

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

Hint

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

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

Solution

考虑整体二分。

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

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

总复杂度 \(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], '\n', 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;
}
posted @ 2019-02-25 13:54  一扶苏一  阅读(239)  评论(0编辑  收藏  举报