[BZOJ3110][ZJOI2013]K大数查询(线段树套线段树)

来源:互联网 发布:彩虹秒赞最新源码 编辑:程序博客网 时间:2024/05/16 12:36

有很多种解法。这里讲一种线段树套线段树的解法。这里外层的线段树是权值线段树,而内层的是位置线段树(保存对应权值范围的出现次数)。在空间问题上,使用动态开点。
对于修改,可以看作是对于权值c,位置区间[a,b]内的所有出现次数加1。也就是说,对于权值线段树从根节点到权值c代表的叶子节点的路径上的所有点所嵌套的位置线段树,都进行一次区间修改,即区间[a,b]1,可以打标记。
对于询问,可以在权值线段树上二分,即如果右子节点(右子权值区间)所嵌套的线段树的[a,b]区间和小于等于c,就往右子树走,否则往左子树走,并且把c减去刚刚的询问结果。走到叶子节点时,答案就是该叶子节点对应的权值。
整体二分解法:http://blog.csdn.net/qq_18455665/article/details/50707462
代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define p2 p << 1#define p3 p << 1 | 1using namespace std;inline int read() {    int res = 0; bool bo = 0; char c;    while (((c = getchar()) < '0' || c > '9') && c != '-');    if (c == '-') bo = 1; else res = c - 48;    while ((c = getchar()) >= '0' && c <= '9')        res = (res << 3) + (res << 1) + (c - 48);    return bo ? ~res + 1 : res;}typedef unsigned int ui;typedef long long ll;const int N = 4e5 + 5, M = 18e6 + 5;int n, m, rt[N], QAQ;struct cyx {    int lc, rc; ui sum, add;    void init() {        lc = rc = sum = add = 0;    }} T[M];inline void modify(const int &l, const int &r, const int &s,const int &e, int &p) {    if (!p) T[p = ++QAQ].init();    if (l == s && r == e) return (void) (T[p].add++);    int mid = l + r >> 1; if (T[p].add) {        if (!T[p].lc) T[T[p].lc = ++QAQ].init();        if (!T[p].rc) T[T[p].rc = ++QAQ].init();        T[T[p].lc].add += T[p].add; T[T[p].rc].add += T[p].add; T[p].add = 0;     }    if (e <= mid) modify(l, mid, s, e, T[p].lc);    else if (s >= mid + 1) modify(mid + 1, r, s, e, T[p].rc);    else modify(l, mid, s, mid, T[p].lc),        modify(mid + 1, r, mid + 1, e, T[p].rc);    T[p].sum = T[T[p].lc].sum + T[T[p].rc].sum +        T[T[p].lc].add * (mid - l + 1) + T[T[p].rc].add * (r - mid);}inline void change(const int &l, const int &r, const int &s,const int &e, const int &v, const int &p) {    modify(1, n, s, e, rt[p]); if (l == r) return; int mid = l + r >> 1;    if (v <= mid) change(l, mid, s, e, v, p2);    else change(mid + 1, r, s, e, v, p3);}inline ui query(const int &l, const int &r, const int &s,const int &e, int &p) {    if (!p) T[p = ++QAQ].init();    if (l == s && r == e) return T[p].sum + T[p].add * (r - l + 1);    int mid = l + r >> 1; if (T[p].add) {        if (!T[p].lc) T[T[p].lc = ++QAQ].init();        if (!T[p].rc) T[T[p].rc = ++QAQ].init();        T[T[p].lc].add += T[p].add; T[T[p].rc].add += T[p].add; T[p].add = 0;     }    ui res; if (e <= mid) res = query(l, mid, s, e, T[p].lc);    else if (s >= mid + 1) res = query(mid + 1, r, s, e, T[p].rc);    else res = query(l, mid, s, mid, T[p].lc) +        query(mid + 1, r, mid + 1, e, T[p].rc);    T[p].sum = T[T[p].lc].sum + T[T[p].rc].sum +        T[T[p].lc].add * (mid - l + 1) + T[T[p].rc].add * (r - mid);    return res;}inline int ask(const int &l, const int &r, const int &s,const int &e, const ll &c, const int &p) {    if (l == r) return l; int mid = l + r >> 1;    ui tmp = query(1, n, s, e, rt[p3]);    if (c <= tmp) return ask(mid + 1, r, s, e, c, p3);    else return ask(l, mid, s, e, c - tmp, p2);}int main() {    int a, b, c, op; n = read(); m = read(); ll d;    while (m--) {        op = read(); a = read(); b = read();        op == 1 ? c = read() : scanf("%lld", &d);        if (op == 1) change(1, n, a, b, c, 1);        else printf("%d\n", ask(1, n, a, b, d, 1));    }    return 0;}
阅读全文
0 0