LuoguP3369

这道题啊。。。

一开始学习的时候遇到了一篇讲的超级好的博客:rentenglong 的博客

这篇大家一定要去瞅瞅,讲的炒鸡详细(就是代码有点锅。。。)

后来找到一份和TA码风差不多的,才完善了一哈qwq

不过最终还是过了

Code:

#include <bits/stdc++.h>
#define root e[0].son[1]
using namespace std;
int read() {
    int re = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -f; ch = getchar();}
    while ('0' <= ch && ch <= '9') {re = re * 10  + ch - '0'; ch = getchar();}
    return re * f;
}
const int N = 1e5 + 3;
const int INF = 1e7 + 3;
int n, cnt;
struct node{
    int v, father;//储存键值,父亲节点 
    int son[2];//存储左右孩子,son[0]为左,son[1]为右 
    int sum;//存储这个节点子树共有多少 元素 (元素包括sum + recy) 
    int recy;//存储相同键值重复多少次 
}e[N];
void update(int x) {//合并 
    e[x].sum = e[e[x].son[0]].sum + e[e[x].son[1]].sum + e[x].recy;
}
int identify(int x) {//确定当前节点与父亲节点的关系 
    return e[e[x].father].son[0] == x ? 0 : 1;
}
void connect(int x, int fa, int son) {//连接两个节点 
    e[x].father = fa;
    e[fa].son[son] = x;
}
void rotate(int x) {//核心函数之一,旋转 
    int y = e[x].father;
    int mroot = e[y].father;
    int mrootson = identify(y);
    int yson = identify(x);
    int B = e[x].son[yson ^ 1];
    connect(B, y, yson);
    connect(y, x, (yson ^ 1));
    connect(x, mroot, mrootson);
    update(y);//y在上,先更新y 
    update(x);
}
void splay(int at, int to) {//核心函数 
    to = e[to].father;
    while (e[at].father != to) {
        int up = e[at].father;
        if (e[up].father == to) {
            rotate(at);
        } else if (identify(at) == identify(up)) {//当自己的父亲与爷爷在一条直线上时,先旋转父亲 
            rotate(up);
            rotate(at);
        } else {//不在同一直线上就旋转两次 
            rotate(at);
            rotate(at);
        }
    }
}
int newpoint(int v, int fa) {//添加新节点 
    e[++cnt].father = fa;
    e[cnt].v = v;
    e[cnt].sum = e[cnt].recy = 1;
    return cnt;
}
void Insert(int x) {
    int now = root;
    if(!root){//特判没根的情况 
        newpoint(x, 0);
        root = cnt;
    } else {
        while (true) {
            e[now].sum++;//经过的点子树中元素都要++ 
            if (e[now].v == x) {
                e[now].recy++;//重复 
                splay(now, root);
                return;
            }
            int next = x < e[now].v ? 0 : 1;//判断该走左孩子还是右孩子 
            if (!e[now].son[next]) {
                int add = newpoint(x, now);
                e[now].son[next] = add;
                splay(add, root);
                return;
            }
            now = e[now].son[next];
        }
    }
}
int find(int v) {//查询键值为v的点的位置 
    int now = root;
    while (true) {
        if (e[now].v == v) {
            splay(now, root);//划重点,下面有用 
            return now;
        }
        int next = v < e[now].v ? 0 : 1;
        if (!e[now].son[next]) {
            return 0;
        }
        now = e[now].son[next];
    }
}
void delet(int x) {//删除节点 
    int now = find(x);//注意find()函数中已经将x转为根节点 
    if (!now) {
        return;
    }
    if (e[now].recy > 1) {//如果有重复,直接减去即可 
        e[now].recy--;
        e[now].sum--;
    } else {
        if (!e[now].son[0] && !e[now].son[1]) {//如果没有左右孩子,说明就一个点 
            root = 0;
        } else if (!e[now].son[0]) {//如果没有左孩子,直接将右孩子提为根节点 
            root = e[now].son[1];
            e[root].father = 0;
        } else {//左右孩子都有,先将左子树中最大的节点转到左孩子的位置,然后提为根节点,把右孩子连到该节点之下 
            int lef = e[now].son[0];
            while (e[lef].son[1]) {//找左子树中最大的节点 
                lef = e[lef].son[1];
            }
            splay(lef, e[now].son[0]);
            connect(e[now].son[1], lef, 1);
            connect(lef, 0, 1);
            update(lef);
        }
    }
}
int _rank(int v) {
    int now = find(v);//因为find()已经将v转为根节点,所以直接求即可 
    return e[e[now].son[0]].sum + 1;
}
int arank(int x) {
    int now = root;
    while (true) {
        int used = e[now].sum - e[e[now].son[1]].sum;
        //如果x大于左子树元素,并且小于等于当前点的左子树的sum加上本节点的recy的值,那么当前的点就是要找的点
        //因为此时说明该x是当前节点重复值中的一个 
        if (e[e[now].son[0]].sum < x && x <= used) {
            splay(now, root);
            return e[now].v;
        }
        if (x < used) {//小于则向左子树寻找 
            now = e[now].son[0];
        } else {//大于则减去该值,再向右子树寻找 
            x -= used;
            now = e[now].son[1];
        }
    }
}
int lower(int v) {//前驱 
    int now = root;
    int ans = -INF;
    while (now) {
        if (e[now].v < v && e[now].v > ans) {
            ans = e[now].v;
        }
        if (v > e[now].v) {
            now = e[now].son[1];
        } else {
            now = e[now].son[0];
        }
    }
    return ans;
}
int upper(int v) {//后继 
    int now = root;
    int ans = INF;
    while(now) {
        if (e[now].v > v && e[now].v < ans) {
            ans = e[now].v;
        }
        if (v < e[now].v) {
            now = e[now].son[0];
        } else {
            now = e[now].son[1];
        }
    }
    return ans;
}
int main () {
    n = read();
    while (n--) {
        int o = read();
        int x = read();
        if (o == 1) {
            Insert(x);
        } else if (o == 2) {
            delet(x);
        } else if (o == 3) {
            printf("%d\n", _rank(x));
        } else if (o == 4) {
            printf("%d\n", arank(x));
        } else if (o == 5) {
            printf("%d\n", lower(x));
        } else if (o == 6) {
            printf("%d\n", upper(x));
        }
    }
    return 0;
}
12-27 17:37