hdu 5412(树套树求第k小数字+离散化)

题意:有n个数字,操作1 l v 表示把第l个数字替换为v,操作2 l r k表示在区间[l,r]内输出第k小数字。
题解:用学长的树套树模板,还需要好好理解。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 200010;
const int M = 200010;
const int INF = 0x3f3f3f3f;

int ctrl[M];
int cnt, n, m;
int P[M], Q[M], a[N], b[N], K[M];

struct treap{
    int key, wei, cnt, size, ch[2];
}T[N * 21];

int tree[N << 1], nodecnt, root;

void init(){
    T[0].size = 0;
    T[0].wei = -INF;
    nodecnt = root = 0;
}

int ID(int l, int r) { return l + r | l != r; }

void update(int x){
    T[x].size = T[T[x].ch[0]].size + T[T[x].ch[1]].size + T[x].cnt;
}

void rotate(int &x,int t){
    int y = T[x].ch[t];
    T[x].ch[t] = T[y].ch[!t];
    T[y].ch[!t] = x;
    update(x);
    update(y);
    x = y;
}

void insert(int &x,int t){
    if (!x){
        x = ++nodecnt;
        T[x].key = t;
        T[x].wei = rand();
        T[x].cnt = 1;
        T[x].ch[0] = T[x].ch[1] = 0;
    } 
    else if (T[x].key == t)
        T[x].cnt++;
    else {
        int k = T[x].key < t;
        insert(T[x].ch[k],t);
        if (T[x].wei < T[T[x].ch[k]].wei) rotate(x,k);
    }
    update(x);
}

void erase(int &x,int t){
    if (T[x].key == t){
        if (T[x].cnt == 1){
            if (!T[x].ch[0] && !T[x].ch[1]) {
                x = 0;return;
            }
            rotate(x,T[T[x].ch[0]].wei < T[T[x].ch[1]].wei);
            erase(x,t);
        }
        else
            T[x].cnt --;
    }
    else
        erase(T[x].ch[T[x].key < t],t);
    update(x);
}

int select(int x,int t){
    if (!x) return 0;
    if (T[x].key > t) return select(T[x].ch[0],t);
    return T[x].cnt + T[T[x].ch[0]].size + select(T[x].ch[1],t);
}

void treeins(int l, int r, int i, int x) {
    insert(tree[ID(l,r)],x);
    if (l == r) return;
    int m = l + r >> 1;
    if (i <= m) treeins(l,m,i,x);
    else treeins(m + 1,r,i,x);
}

void treedel(int l, int r, int i, int x) {
    erase(tree[ID(l,r)],x);
    if (l == r) return;
    int m = l + r >> 1;
    if (i <= m) treedel(l,m,i,x);
    else treedel(m + 1,r,i,x);
}

int query(int l, int r, int x, int y, int t) {
    if (l == r) return l;
    int m = l + r >> 1;
    int ans = select(tree[ID(l,m)],y) - select(tree[ID(l,m)],x);
    if (ans >= t) return query(l,m,x,y,t);
    return query(m + 1,r,x,y,t - ans);
}

inline void scanf_(int &num)
{
    char in;
    while ((in = getchar()) > '9' || in < '0') ;
    num = in - '0';
    while (in = getchar(), in >= '0' && in <= '9')
        num *= 10, num += in - '0';
}

int main() {
    while (~scanf("%d", &n)) {
        memset(tree,0,sizeof tree);
        init();
        cnt = 0;
        for (int i = 1; i <= n; i++) {
            scanf_(a[i]);
            b[++cnt] = a[i];
        }
        scanf("%d", &m);
        for (int i = 1; i <= m; i++) {
            scanf_(ctrl[i]);
            scanf_(P[i]);
            scanf_(Q[i]);
            if (ctrl[i] == 2)
                scanf_(K[i]);
            else b[++cnt] = Q[i];
        }
        sort(b + 1, b + 1 + cnt);
        cnt = unique(b + 1, b + 1 + cnt) - b - 1;
        for (int i = 1; i <= n; i++) {
            a[i] = lower_bound(b + 1, b + 1 + cnt, a[i]) - b;
            treeins(1, cnt, a[i], i);
        }
        for (int i = 1; i <= m; i++) {
            if (ctrl[i] == 2) {
                int id = query(1, cnt, P[i] - 1, Q[i], K[i]);
                printf("%d\n", b[id]);
            }
            else {
                treedel(1, cnt, a[P[i]], P[i]);
                a[P[i]] = lower_bound(b + 1, b + 1 + cnt, Q[i]) - b;
                treeins(1, cnt, a[P[i]], P[i]);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值