hdu 5412 CRB and Queries(树套树模板,区间第K大)

题意:

给出一串数字,然后给出两种操作:
1. 1 L V 操作一:把下标为L的点的值替换为 V
2. 2 L R K 操作二:在 [L,R] 区间求第K大

解析:

本模板转载自
http://blog.csdn.net/u012860063/article/details/47813079

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 600010;
const int M = 100010;

struct Treap {
    int key,wht,count,sz,ch[2];
} tp[N<<4];

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

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

void init() {
    tp[0].sz = 0;
    tp[0].wht = -INF;
    nodeCount = 0;
    root = 0;
}

void update(int x) {
    tp[x].sz = tp[tp[x].ch[0]].sz + tp[x].count + tp[tp[x].ch[1]].sz;
}

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

void insert(int &x, int t) {
    if(!x) {
        x = ++nodeCount;
        tp[x].key = t;
        tp[x].wht = rand();
        tp[x].count = 1;
        tp[x].ch[0] = tp[x].ch[1]=0;
    }else if(tp[x].key == t)
        tp[x].count++;
    else {
        int k = tp[x].key < t;
        insert(tp[x].ch[k],t);
        if(tp[x].wht<tp[tp[x].ch[k]].wht)
            rotate(x,k);
    }
    update(x);
}

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

int select(int x,int t) {
    if(!x) return 0;
    if(tp[x].key>t) return select(tp[x].ch[0],t);
    return tp[x].count + tp[tp[x].ch[0]].sz + select(tp[x].ch[1],t);
}

int a[N], b[N], ord[M][5], tot;
int n, m;

int search(int x) {
    int l = 1, r = tot, mid;
    while (l<=r) {
        mid = (l+r)>>1;
        if(b[mid]==x) return mid;
        if(b[mid]<x) l = mid+1;
        else r = mid-1;
    }
}

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

void treeDel(int l,int r,int i,int x) {
    erase(tree[idx(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 k) {
    if(l==r) return l;
    int m=(l+r)>>1;
    int ans=select(tree[idx(l,m)],y) - select(tree[idx(l,m)],x);
    if(ans>=k) return query(l,m,x,y,k);
    return query(m+1,r,x,y,k-ans);
}

int main() {
    while (~scanf("%d",&n)) {
        tot = 0;
        memset(tree,0,sizeof(tree));
        init();
        for(int i=1; i<=n; i++) {
            scanf("%d",&a[i]);
            b[++tot] = a[i];
        }
        scanf("%d",&m);
        for(int i=1; i<=m; i++) {
            int op;
            int x,y,c;
            scanf("%d",&op);
            if(op == 2) {
                scanf("%d%d%d",&x,&y,&c);
                ord[i][1]=1;
                ord[i][2]=x; ord[i][3]=y; ord[i][4]=c;
            }else {
                scanf("%d%d",&x,&y);
                ord[i][1]=2;
                ord[i][2]=x; ord[i][3]=y;
                b[++tot]=y;
            }
        }

        sort(b+1,b+1+tot);
        tot = unique(b+1, b+1+tot) - b;

        for(int i=1; i<=n; i++) {
            a[i]=search(a[i]);
            treeInsert(1,tot,a[i],i);
        }

        for(int i=1; i<=m; i++) {
            if(ord[i][1]==1)
                printf("%d\n",b[query(1, tot, ord[i][2]-1, ord[i][3], ord[i][4])]);
            else {
                treeDel(1, tot, a[ord[i][2]], ord[i][2]);
                a[ord[i][2]] = search(ord[i][3]);
                treeInsert(1, tot, a[ord[i][2]], ord[i][2]);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值