[BZOJ1861]书架 Treap

Treap

Treap的从左到右比较关键字为位置

将一本书拿到 第一个/最后一个 相当于给这本书一个 大于/小于 所有书的优先值,删除后重新插入即可

交换两本书可以直接交换他们的优先值

剩下的是查询第k大以及一个值的名次

注意明确数组的定义


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
 
#define N 1000500 
 
using namespace std;
int s[N][2],tr[N],rnd[N],d[N],h[N],siz[N],e[N];
int n,m,x,w,rt,L,R,v,r,ans,cnt;
 
inline void update(int t) {
    siz[t] = siz[ s[t][0] ] + siz[ s[t][1] ] + 1;
}
void lturn(int &t) {
    int d = s[t][1];
    s[t][1] = s[d][0];
    s[d][0] = t;
    update(t); update(d);
    t = d;
}
 
void rturn(int &t) {
    int d = s[t][0];
    s[t][0] = s[d][1];
    s[d][1] = t; 
    update(t); update(d); 
    t = d;
}
 
void ins(int x,int &t) {
    if (!t) {
        tr[ t=++cnt ] = x;
        h[t] = w;
        rnd[t] = rand(); 
        siz[t] = 1;
        update(t); 
        return ; 
    }
    siz[t]++;
    if (x <= tr[t]) {
        ins(x,s[t][0]);
        if (rnd[ s[t][0] ] > rnd[t]) rturn(t);
    } else {
        ins(x,s[t][1]);
        if (rnd[ s[t][1] ] > rnd[t]) lturn(t);
    }
}
 
void del(int x,int &t) {
    if (!t) return ;
    if (x == tr[t]) {
        if ((!s[t][0]) || (!s[t][1])) {
            tr[t] = 0;
            t = s[t][0] + s[t][1];
            return ;
        }
        if (rnd[ s[t][0] ] > rnd[ s[t][1] ]) {
            rturn(t); siz[t]--; del(x,s[t][1]);
        } else {
            lturn(t); siz[t]--; del(x,s[t][0]);
        }
        return ;
    }
    siz[t]--;
    if (x < tr[t]) del(x,s[t][0]); else del(x,s[t][1]);
}
 
void query(int x,int t) {
    if (x == tr[t]) { ans += siz[ s[t][0] ] + 1; return ; }
    if (x < tr[t]) 
        query(x,s[t][0]); 
    else
        ans += siz[ s[t][0] ] + 1 , query(x,s[t][1]);
}
 
void kth(int k,int t) {
    if (!t) return ;
    int tmp = siz[ s[t][0] ] + 1;
    if (tmp == k) { r = h[t]; return ; }
    if (tmp > k) kth(k,s[t][0]); else kth(k-tmp,s[t][1]);
}
 
 
bool cmp(int p1,int p2) { return d[p1] < d[p2]; }
void debug() {
    for (int i=1;i<=n;i++) e[i] = i;
    sort(e+1,e+n+1,cmp);
}
 
void solve() {
    scanf("%d%d",&n,&m); L = 1; R = n;
    for (int i=1;i<=n;i++) { 
        scanf("%d",&w); 
        d[w] = i;
        ins(i,rt);
    }
    while (m--) {
        //debug();
        char cmd[10]; scanf("%s",cmd+1);
        if (cmd[1] == 'T') {
            scanf("%d",&w);
            del(d[w],rt);
            d[w] = --L;
            ins(d[w],rt);
            continue;
        }
        if (cmd[1] == 'B') {
            scanf("%d",&w);
            del(d[w],rt);
            d[w] = ++R;
            ins(d[w],rt);
            continue;
        }
        if (cmd[1] == 'I') {
            int xx,tt,r1,r2;scanf("%d%d",&xx,&tt); 
            if (tt == 0) continue;
            ans = 0;
            query(d[xx],rt); r1 = ans;
            kth(r1+tt,rt);   r2 = r;
            r1 = xx;
             
            del(d[r1],rt);
            del(d[r2],rt);
            swap(d[r1],d[r2]);
            w = r1; ins(d[r1],rt);
            w = r2; ins(d[r2],rt);
            continue;
        }
        if (cmd[1] == 'A') {
            ans = 0;
            scanf("%d",&x);
            query(d[x],rt);
            printf("%d\n",ans-1);
            continue;
        }
        if (cmd[1] == 'Q') {
            scanf("%d",&x);
            kth(x,rt);
            printf("%d\n",r);
            continue;
        }
    }
}
 
int main() {
    solve();
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值