bzoj3196: Tyvj 1730 二逼平衡树

27 篇文章 0 订阅
10 篇文章 0 订阅

题面在这里


我去树套树真**丧心病狂…
神tm6KB代码,代码总长233行也是醉了。

做法:
额没什么好说的就是树套树的裸题。。自行体会。

/*************************************************************
    Problem: bzoj 3196 Tyvj 1730 二逼平衡树
    User: fengyuan
    Language: C++
    Result: Accepted
    Time: 8504 ms
    Memory: 126296 kb
    Submit_Time: 2017-12-07 20:42:07
*************************************************************/

#include<bits/stdc++.h>
#define rep(i, x, y) for (int i = (x); i <= (y); i ++)
#define down(i, x, y) for (int i = (x); i >= (y); i --)
#define mid ((l+r)/2)
#define lc (o<<1)
#define rc (o<<1|1)
#define pb push_back
#define mp make_pair
#define PII pair<int, int>
#define F first
#define S second
#define B begin()
#define E end()
using namespace std;
typedef long long LL;
//head

const int N = 4000010;
const int INF = 1e9;
int n, m, tot, ans, MX;
int a[N], sz[N], cnt[N], ch[N][2], fa[N], data[N], rt[N];

//=====================================================================
//平衡树

inline void splayClear(int x)
{
    fa[x] = ch[x][0] = ch[x][1] = sz[x] = cnt[x] = data[x] = 0;
}

inline void pushup(int x)
{
    sz[x] = (ch[x][0]?sz[ch[x][0]]:0) + (ch[x][1]?sz[ch[x][1]]:0) + cnt[x];
}

inline void rot(int x)
{
    int y = fa[x], z = fa[y]; bool f = ch[y][1] == x;
    ch[y][f] = ch[x][f^1]; if (ch[x][f^1]) fa[ch[x][f^1]] = y;
    fa[x] = z; if (z) ch[z][ch[z][1] == y] = x;
    fa[y] = x; ch[x][f^1] = y;
    pushup(y); pushup(x);
}

inline void splay(int i, int x, int top)
{
    while (fa[x] != top){
        int y = fa[x], z = fa[y];
        if (z != top) rot((ch[z][0] == y) == (ch[y][0] == x) ? y : x);
        rot(x);
    }
    if (!top) rt[i] = x;
}

inline void splayInsert(int i, int v)
{
    int x = rt[i];
    if (!rt[i]){
        rt[i] = x = ++ tot;
        data[x] = v; sz[x] = cnt[x] = 1;
        fa[x] = ch[x][0] = ch[x][1] = 0;
        return;
    } int last = 0;
    while (1){
        if (data[x] == v){ cnt[x] ++; pushup(last); break; }
        last = x;
        x = ch[x][v > data[x]];
        if (!x){
            x = ++ tot; data[x] = v; sz[x] = cnt[x] = 1;
            ch[last][v > data[last]] = x;
            fa[x] = last; ch[x][0] = ch[x][1] = 0;
            pushup(last); break;
        }
    }
    splay(i, x, 0);
}

inline int splayRank(int i, int v)//在第i棵splay中求比v小的数的个数
{
    int x = rt[i], ret = 0;
    while (x){
        if (data[x] == v) return ret + ((ch[x][0])?sz[ch[x][0]]:0);
        if (data[x] < v){
            ret += ((ch[x][0])?sz[ch[x][0]]:0) + cnt[x];
            x = ch[x][1];
        } else x = ch[x][0];
    }
    return ret;
}

inline int splayFind(int i, int v)//在第i棵splay中找到值为v的节点并将它提升到根
{
    int x = rt[i];
    while (x){
        if (data[x] == v){ splay(i, x, 0); return x; }
        x = ch[x][v > data[x]];
    }
}

inline int splayPre(int i){ int x = ch[rt[i]][0]; while (ch[x][1]) x = ch[x][1]; return x; }
inline int splaySuc(int i){ int x = ch[rt[i]][1]; while (ch[x][0]) x = ch[x][0]; return x; }

inline void splayDelete(int i, int key)//将第i棵splay的值为key的元素删掉 
{
    int x = splayFind(i, key);
    if (cnt[x] > 1){ cnt[x] --; pushup(x); return; }
    if (!ch[x][0] && !ch[x][1]){ splayClear(rt[i]); rt[i] = 0; return; }
    if (!ch[x][0]){
        int y = ch[x][1]; rt[i] = y; fa[y] = 0;
        return;
    }
    if (!ch[x][1]){
        int y = ch[x][0]; rt[i] = y; fa[y] = 0;
        return;
    }
    int p = splayPre(i); int oldrt = rt[i];
    splay(i, p, 0);
    ch[rt[i]][1] = ch[oldrt][1]; fa[ch[oldrt][1]] = rt[i];
    splayClear(oldrt);
    pushup(rt[i]);
}

inline int splayGetpre(int i, int v)
{
    int x = rt[i];
    while (x){
        if (data[x] < v){
            if (ans < data[x]) ans = data[x];
            x = ch[x][1];
        } else x = ch[x][0];
    } return ans;
}

inline int splayGetsuc(int i, int v)
{
    int x = rt[i];
    while (x){
        if (data[x] > v){
            if (ans > data[x]) ans = data[x];
            x = ch[x][0];
        } else x = ch[x][1];
    } return ans;
}

//=====================================================================
//线段树

inline void segInsert(int o, int l, int r, int x, int w)
{
    splayInsert(o, w);
    if (l == r) return;
    if (x <= mid) segInsert(lc, l, mid, x, w);
    else segInsert(rc, mid+1, r, x, w);
}

inline void segRank(int o, int l, int r, int x, int y, int v)
{
    if (l == x && r == y){ ans += splayRank(o, v); return; }
    if (y <= mid) segRank(lc, l, mid, x, y, v);
    else if (x > mid) segRank(rc, mid+1, r, x, y, v);
    else segRank(lc, l, mid, x, mid, v), segRank(rc, mid+1, r, mid+1, y, v);
}

inline void segChange(int o, int l, int r, int x, int v)
{
    splayDelete(o, a[x]); splayInsert(o, v);
    if (l == r){ a[x] = v; return; }
    if (x <= mid) segChange(lc, l, mid, x, v);
    else segChange(rc, mid+1, r, x, v);
}

inline void segPre(int o, int l, int r, int x, int y, int v)
{
    if (l == x && r == y){ ans = max(ans, splayGetpre(o, v)); return; }
    if (y <= mid) segPre(lc, l, mid, x, y, v);
    else if (x > mid) segPre(rc, mid+1, r, x, y, v);
    else segPre(lc, l, mid, x, mid, v), segPre(rc, mid+1, r, mid+1, y, v);
}

inline void segSuc(int o, int l, int r, int x, int y, int v)
{
    if (l == x && r == y){ ans = min(ans, splayGetsuc(o, v)); return; }
    if (y <= mid) segSuc(lc, l, mid, x, y, v);
    else if (x > mid) segSuc(rc, mid+1, r, x, y, v);
    else segSuc(lc, l, mid, x, mid, v), segSuc(rc, mid+1, r, mid+1, y, v);
}

//=====================================================================
//第二问

inline int getKth(int x, int y, int k)
{
    int ll = 0, rr = MX+1, mm;
    while (ll < rr){
        mm = (ll + rr) / 2;
        ans = 0; segRank(1, 1, n, x, y, mm);
        if (ans < k) ll = mm+1;
        else rr = mm;
    }
    return ll-1;
}

//=====================================================================
//main

int main()
{
    scanf("%d%d", &n, &m);
    rep(i, 1, n){
        scanf("%d", &a[i]);
        segInsert(1, 1, n, i, a[i]);
        MX = max(MX, a[i]);
    }
    while (m --){
        int opt, x, y, z; scanf("%d%d%d", &opt, &x, &y);
        if (opt == 1) scanf("%d", &z), ans = 0, segRank(1, 1, n, x, y, z), printf("%d\n", ans+1);
        else if (opt == 2) scanf("%d", &z), printf("%d\n", getKth(x, y, z));
        else if (opt == 3) segChange(1, 1, n, x, y);
        else if (opt == 4) scanf("%d", &z), ans = -INF, segPre(1, 1, n, x, y, z), printf("%d\n", ans);
        else scanf("%d", &z), ans = INF, segSuc(1, 1, n, x, y, z), printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值