BZOJ 3196 [树套树]

Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询 k 在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询 k 在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询 k 在区间内的后继(后继定义为大于x,且最小的数)
Input
第一行两个数 n,m 表示长度为 n 的有序序列和m个操作
第二行有 n 个数,表示有序序列
下面有m行, opt 表示操作标号
opt=1 则为操作 1 ,之后有三个数l,r,k表示查询 k 在区间[l,r]的排名
opt=2 则为操作 2 ,之后有三个数l,r,k表示查询区间 [l,r] 内排名为 k 的数
opt=3则为操作 3 ,之后有两个数pos,k表示将 pos 位置的数修改为 k
opt=4则为操作 4 ,之后有三个数l,r,k表示查询区间 [l,r] k 的前驱
opt=5则为操作 5 ,之后有三个数l,r,k表示查询区间 [l,r] k 的后继

很显然的树套树。。。。
我是线段树套Treap树的。。。。
但不知道为什么 Linux 下一直RE啊QAQ
BZOJ 管理员那里要来的数据 windows 下测都能过的QAQ

#include <cstdio>
#include <cstdlib>

inline int Max(int a, int b) {
    return a > b ? a : b;
}
inline int Min(int a, int b) {
    return a < b ? a : b;
}

inline char get(void) {
    static char buf[1000000], *p1 = buf, *p2 = buf;
    if (p1 == p2) {
        p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
        if (p1 == p2) return EOF;
    }
    return *p1++;
}
inline void read(int &x) {
    x = 0; char c = get(); int sign = 1;
    for (; c < '0' || c > '9'; c = get()) if(c == '-') sign = 0;
    for (; c >= '0' && c <= '9'; x = (x << 1) + (x << 3) + c - '0', c = get());
    x = sign ? x : -x;
}

const int N = 50010, INF = 1 << 30;

struct node {
    node *ch[2];
    int key, pri, size, num;
    inline void maintain(void) {
        size = ch[0]->size + ch[1]->size + num;
    }
    inline int cmp(int x) {
        return x == key ? -1 : x > key;
    }
    inline int cmpk(int k) {
        int d = k - ch[0]->size;
        return d == 1 ? -1 : d > 1;
    }
};
node mem[N << 6];
node *Tail, *null, *t;
void Init(void) {
    Tail = mem; null = Tail++;
    null->ch[0] = null->ch[1] = null;
    null->size = null->key = null->pri = null->num = 0;
}
inline node* NewNode(int key) {
    node* p = Tail++; p->key = key;
    p->size = 1; p->pri = rand();
    p->ch[0] = p->ch[1] = null; p->num = 1;
}
struct Treap {
private:
    node *rt;
    void Rotate(node* &o, int d) {
        node *k = o->ch[d ^ 1];
        o->ch[d ^ 1] = k->ch[d];
        k->ch[d] = o; o->maintain();
        k->maintain(); o = k;
    }
    void Insert(node* &o, int x) {
        int d = o->cmp(x);
        if (d == -1) {
            o->num++; o->size++; return;
        }
        if (o->ch[d] == null) {
            o->ch[d] = NewNode(x);
            if (o->ch[d]->pri > o->pri) Rotate(o, d ^ 1);
            o->maintain();
            return;
        }
        Insert(o->ch[d], x);
        if (o->ch[d]->pri > o->pri) Rotate(o, d ^ 1);
        o->maintain();
    }
    void Remove(node* &o, int x) {
        int d = o->cmp(x);  
        if (d == -1) {
            if (o->num == 1) {  
                if (o->ch[0] != null && o->ch[1] != null) {  
                    int d2 = o->ch[0]->pri > o->ch[1]->pri;  
                    Rotate(o, d2); Remove(o->ch[d2], x);  
                } else {  
                    if (o->ch[0] != null) o = o->ch[0];
                    else if (o->ch[1] != null) o = o->ch[1];  
                    else o = null;  
                }  
            } else {  
                o->num--; o->size--;
            }  
        } else {  
            Remove(o->ch[d], x);  
        }  
        if (o != null) o->maintain();
    }
    int Pre(node* o, int x) {
        if (o == null) return 0;
        if (o->key < x) return Max(Pre(o->ch[1], x), o->key);
        else return Pre(o->ch[0], x);
    }
    int Suc(node* o, int x) {
        if (o == null) return INF;
        if (o->key > x) return Min(Suc(o->ch[0], x), o->key);
        else return Suc(o->ch[1], x);
    }
    int GetRank(node* o, int x) {
        if (o == null) return 0;
        int d = o->cmp(x);
        if (d == -1) return o->ch[0]->size;
        if (d) return GetRank(o->ch[1], x) + o->ch[0]->size + o->num;
        else return GetRank(o->ch[0], x);
    }
public:
    inline void Insert(int x) {
        if (rt == NULL) rt = NewNode(x);
        else Insert(rt, x);
    }
    inline void Modify(int x, int y) {
        Remove(rt, x); Insert(rt, y);
    }
    inline int Rank(int x) {
        return GetRank(rt, x);
    }
    inline int Pre(int x) {
        return Pre(rt, x);
    }
    inline int Suc(int x) {
        return Suc(rt, x);
    }
};

Treap T[N << 5];
int a[N];
int n, m, x, y, z, opt, res, cnt;

void Build(int o, int l, int r) {
    for (int i = l; i <= r; i++) T[o].Insert(a[i]);
    if (l == r) return;
    int mid = (l + r) >> 1;
    Build(o << 1, l, mid);
    Build(o << 1 | 1, mid + 1, r);
}
int Rank(int o, int l, int r, int L, int R, int x) {
    if (l >= L && r <= R) return T[o].Rank(x);
    int mid = (l + r) >> 1, res = 0;
    if (L <= mid) res += Rank(o << 1, l, mid, L, R, x);
    if (R > mid) res += Rank(o << 1 | 1, mid + 1, r, L, R, x);
    return res;
}
int Kth(int L, int R, int k) {
    int l = 1, r = INF, mid, pos;
    while (l <= r) {
        mid = (l + r) >> 1;
        if (Rank(1, 1, n, L, R, mid) + 1 <= k) {
            pos = mid; l = mid + 1;
        } else {
            r = mid - 1;
        }
    }
    return pos;
}
void Modify(int o, int l, int r, int pos, int x) {
    T[o].Modify(a[pos], x);
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (pos <= mid) Modify(o << 1, l, mid, pos, x);
    else Modify(o << 1 | 1, mid + 1, r, pos, x);
}
int Pre(int o, int l, int r, int L, int R, int x) {
    if (l >= L && r <= R) return T[o].Pre(x);
    int mid = (l + r) >> 1, res = 0;
    if (L <= mid) res = Max(Pre(o << 1, l, mid, L, R, x), res);
    if (R > mid) res = Max(Pre(o << 1 | 1, mid + 1, r, L, R, x), res);
    return res;
}
int Suc(int o, int l, int r, int L, int R, int x) {
    if (l >= L && r <= R) return T[o].Suc(x);
    int mid = (l + r) >> 1, res = INF;
    if (L <= mid) res = Min(Suc(o << 1, l, mid, L, R, x), res);
    if (R > mid) res = Min(Suc(o << 1 | 1, mid + 1, r, L, R, x), res);
    return res;
}

int main(void) {
    read(n); read(m); Init();
    for (int i = 1; i <= n; i++) read(a[i]);
    Build(1, 1, n); t = null;
    for (int i = 0; i < m; i++) {
        read(opt); read(x); read(y);
        if (opt == 1) {
            read(z); printf("%d\n", Rank(1, 1, n, x, y, z) + 1);
        } else if (opt == 2) {
            read(z); printf("%d\n", Kth(x, y, z));
        } else if (opt == 3) {
            Modify(1, 1, n, x, y); a[x] = y;
        } else if (opt == 4) {
            read(z); printf("%d\n", Pre(1, 1, n, x, y, z));
        } else {
            read(z); printf("%d\n", Suc(1, 1, n, x, y, z));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值