树套树模板 (二逼平衡树)

树套树基础题。

我用线段树套无旋treap解决的这道题。

用线段树维护区间,每个线段树节点内部是一棵平衡树, 平衡树内存储区间[L,R]的节点信息。

不开O2会T掉一个点...可能是我自带大常数...

但自我感觉实现得非常优美...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
#define reg register
inline int read() {
    int res = 0;char ch = getchar();bool fu = 0;
    while(!isdigit(ch)) fu |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) res = (res << 3) + (res << 1) + (ch ^ 48), ch = getchar();
    return fu ? -res : res;
}
#define N 500005
int n, m, chushi[N], MAX;
namespace treap {
    int val[N * 50], siz[N * 50], ch[N * 50][2], pri[N * 50], tot;
    inline void update(int o) {
        siz[o] = siz[ch[o][0]] + siz[ch[o][1]] + 1;
    }
    inline int newnode(int v) {
        int jd = ++tot;
        siz[jd] = 1;
        val[jd] = v, pri[jd] = rand();
        return jd;
    }
    int Merge(int x, int y) 
    {
        if (x * y == 0) return x + y;
        if (pri[x] < pri[y]) {
            ch[x][1] = Merge(ch[x][1], y);
            update(x);
            return x;
        } else {
            ch[y][0] = Merge(x, ch[y][0]);
            update(y);
            return y;
        }
    }
    void Split(int o, int k, int &x, int &y) 
    {
        if (!o) {x = y = 0;return;}
        if (val[o] <= k) x = o, Split(ch[x][1], k, ch[x][1], y);
        else y = o, Split(ch[y][0], k, x, ch[y][0]);
        update(o);
    }
    inline void insert(int &root, int v) 
    {
        int a = 0, b = 0;
        Split(root, v, a, b);
        root = Merge(Merge(a, newnode(v)), b);
    }
    inline void delet(int &root, int v)
    {
        int a = 0, b = 0, c = 0;
        Split(root, v, a, b);
        Split(a, v - 1, a, c);
        c = Merge(ch[c][0], ch[c][1]);
        root = Merge(Merge(a, c), b);
    }
    inline int rnk(int &root, int v) 
    {
        int a = 0, b = 0;
        Split(root, v - 1, a, b);
        int res = siz[a] - 1;//
        root = Merge(a, b);
        return res;
    }
    inline int kth(int o, int k) 
    {
        while(1) {
            if (siz[ch[o][0]] >= k) o = ch[o][0];
            else if (siz[ch[o][0]] + 1 == k) return val[o];
            else k -= siz[ch[o][0]] + 1, o = ch[o][1];
        }
    }
    inline int findpre(int &root, int v) 
    {
        int a = 0, b = 0;
        Split(root, v - 1, a, b);
        int res = kth(a, siz[a]);
        root = Merge(a, b);
        return res;
    }
    inline int findnxt(int &root, int v)
    {
        int a = 0, b = 0;
        Split(root, v, a, b);
        int res = kth(b, 1);
        root = Merge(a, b);
        return res;
    }
}
int rt[N << 2];
#define ls o << 1
#define rs o << 1 | 1
void Build(int l, int r, int o)
{
    treap::insert(rt[o], 2147483647);
    treap::insert(rt[o], -2147483647);
    for (reg int i = l ; i <= r ; i ++) treap :: insert(rt[o], chushi[i]);
    if (l == r) return ;
    int mid = (l + r) >> 1;
    Build(l, mid, ls), Build(mid + 1, r, rs);
}
int queryrank(int l, int r, int o, int ql, int qr, int v)
{
    if (l >= ql and r <= qr) return treap::rnk(rt[o], v);
    int res = 0;
    int mid = (l + r) >> 1;
    if (ql <= mid) res += queryrank(l, mid, ls, ql, qr, v);
    if (qr > mid) res += queryrank(mid + 1, r, rs, ql, qr, v);
    return res;
}
inline int kth(int ql, int qr, int k)
{
    int l = 0, r = MAX;
    int res = 0;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if (queryrank(1, n, 1, ql, qr, mid) + 1 <= k) res = mid, l = mid + 1;
        else r = mid - 1;
    }
    return res;
}
void change(int l, int r, int o, int pos, int v, int yuanshi)
{
    if (l == r) {treap::delet(rt[o], chushi[l]), chushi[l] = v, treap::insert(rt[o], v);return;}
    treap::delet(rt[o], yuanshi), treap::insert(rt[o], v);
    int mid = (l + r) >> 1;
    if (pos <= mid) change(l, mid, ls, pos, v, yuanshi);
    else change(mid + 1, r, rs, pos, v, yuanshi);
}
int ans;
void querypre(int l, int r, int o, int ql, int qr, int v)
{
    if (l >= ql and r <= qr) {ans = max(ans, treap::findpre(rt[o], v));return;}
    int mid = (l + r) >> 1;
    if (ql <= mid) querypre(l, mid, ls, ql, qr, v);
    if (qr > mid) querypre(mid + 1, r, rs, ql, qr, v);
}
void querynxt(int l, int r, int o, int ql, int qr, int v)
{
    if (l >= ql and r <= qr) {ans = min(ans, treap::findnxt(rt[o], v));return;}
    int mid = (l + r) >> 1;
    if (ql <= mid) querynxt(l, mid, ls, ql, qr, v);
    if (qr > mid) querynxt(mid + 1, r, rs, ql, qr, v);
}

int main()
{
    n = read(), m = read();
    for (reg int i = 1 ; i <= n ; i ++) chushi[i] = read(), MAX = max(MAX, chushi[i]);
    Build(1, n, 1);
    while(m--)
    {
        int opt = read(), l = 0, r = 0, p = 0, v = 0;
        if (opt == 1) l = read(), r = read(), v = read(), printf("%d\n", queryrank(1, n, 1, l, r, v) + 1);
        else if (opt == 2) l = read(), r = read(), v = read(), printf("%d\n", kth(l, r, v));
        else if (opt == 3) p = read(), v = read(), change(1, n, 1, p, v, chushi[p]);
        else if (opt == 4) l = read(), r = read(), v = read(), ans = -2147483647, querypre(1, n, 1, l, r, v), printf("%d\n", ans);
        else l = read(), r = read(), v = read(), ans = 2147483647, querynxt(1, n, 1, l, r, v), printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2019-02-16 22:08  zZhBr  阅读(166)  评论(0编辑  收藏  举报