传送门
这道题用各种平衡树都能过. 什么Splay、Treap、SBT、替罪羊树, 红黑树等等. 因为最近学LCT用的是splay, 所以就用的平衡树来写的.
这里面没有翻转操作, 我知道是打个标记即可, 可是真正的做翻转序列的题, 还是不太会啊…
AC Code
const int inf = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
int root = 0, tot;
struct Node {
int fa, son[2], cnt, val, scnt;
}t[maxn];
void update(int u) {
t[u].scnt = t[t[u].son[0]].scnt + t[t[u].son[1]].scnt + t[u].cnt;
}
bool nroot(int x) {
return t[t[x].fa].son[0] == x || t[t[x].fa].son[1] == x;
}
void rot(int x) {
int fa = t[x].fa, gfa = t[t[x].fa].fa;
int k = (x == t[fa].son[1]);
t[fa].son[k] = t[x].son[k^1];
if(nroot(fa)) t[gfa].son[fa == t[gfa].son[1]] = x;
if(t[x].son[k^1]) t[t[x].son[k^1]].fa = fa;
t[x].son[k^1] = fa;
t[fa].fa = x; t[x].fa = gfa;
update(fa); update(x);
}
void splay(int x, int pos) {
for(int fa ; t[x].fa != pos ; rot(x)) {
if (fa = t[x].fa, t[fa].fa != pos)
rot((t[x].son[0] == x) ^ (t[fa].son[0] == fa) ? fa : x);
}
if(!pos) root = x;
}
void Insert(int x) {
int u = root, pre = 0;
while(u && t[u].val != x) {
pre = u;
u = t[u].son[x > t[u].val];
}
if(u) t[u].cnt++;
else {
u = ++tot;
if(pre) t[pre].son[x > t[pre].val] = u;
t[tot].son[0] = t[tot].son[1] = 0;
t[tot].fa = pre; t[tot].val = x;
t[tot].cnt = 1; t[tot].scnt = 1;
}
splay(u, 0);
}
void Find(int x) {
int u = root;
if(!u) return;
while(t[u].son[x > t[u].val] && x != t[u].val)
u = t[u].son[x > t[u].val];
splay(u, 0);
}
int Next(int x, int f) {
Find(x);
int u = root;
if((t[u].val > x && f) || (t[u].val < x && !f)) return u;
u = t[u].son[f];
while(t[u].son[f^1]) u = t[u].son[f^1];
return u;
}
void Delete(int x) {
int last = Next(x, 0);
int next = Next(x, 1);
splay(last, 0); splay(next, last);
int del = t[next].son[0];
if(t[del].cnt > 1) {
t[del].cnt--;
splay(del, 0);
}
else t[next].son[0] = 0;
}
int K_th(int x) {
int u = root;
if(t[u].scnt < x)
return -1;
while(1) {
int y = t[u].son[0];
if(x > t[y].scnt + t[u].cnt) {
x -= t[y].scnt + t[u].cnt;
u = t[u].son[1];
}
else if(t[y].scnt >= x) u = y;
else return t[u].val;
}
}
void solve() {
Insert(-inf); Insert(inf);
int n; scanf("%d", &n);
while(n--) {
int op, x; scanf("%d%d", &op, &x);
if(op == 1) Insert(x);
else if(op == 2) Delete(x);
else if (op == 3) {
Find(x); printf("%d\n", t[t[root].son[0]].scnt);
}
else if (op == 4) printf("%d\n", K_th(x+1));
else if (op == 5) printf("%d\n", t[Next(x, 0)].val);
else printf("%d\n", t[Next(x, 1)].val);
}
}
避免忘记, 附上解释版
const int inf = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
int root = 0, tot;
struct Node {
int fa, son[2], cnt, val, scnt;
// 父亲, 两个儿子, 自身的数量, 值, 儿子和自身一共的数量
}t[maxn];
void update(int u) { // 计算儿子数量
t[u].scnt = t[t[u].son[0]].scnt + t[t[u].son[1]].scnt + t[u].cnt;
}
bool nroot(int x) {
return t[t[x].fa].son[0] == x || t[t[x].fa].son[1] == x;
}
void rot(int x) {
int fa = t[x].fa, gfa = t[t[x].fa].fa;
int k = (x == t[fa].son[1]);
t[fa].son[k] = t[x].son[k^1];
if(nroot(fa)) t[gfa].son[fa == t[gfa].son[1]] = x;
if(t[x].son[k^1]) t[t[x].son[k^1]].fa = fa;
t[x].son[k^1] = fa;
t[fa].fa = x; t[x].fa = gfa;
update(fa); update(x);
}
void splay(int x, int pos) { //把x节点旋转到目标位置
for(int fa ; t[x].fa != pos ; rot(x)) {
if (fa = t[x].fa, t[fa].fa != pos)
rot((t[x].son[0] == x) ^ (t[fa].son[0] == fa) ? fa : x);
}
if(!pos) root = x; //当前的根节点
}
void Insert(int x) { //插入x
int u = root, pre = 0;
while(u && t[u].val != x) {
pre = u;
u = t[u].son[x > t[u].val];
}
if(u)//已经有这个数字了
t[u].cnt++;//计算数字个数
else {//不存在这个数字,加入新的节点
u = ++tot;//总的节点数
if(pre) t[pre].son[x > t[pre].val] = u;
t[tot].son[0] = t[tot].son[1] = 0;
t[tot].fa = pre; t[tot].val = x;
t[tot].cnt = 1; t[tot].scnt = 1;
}
splay(u, 0); // 继续保持平衡
}
void Find(int x) { //查找x的位置(或者是最接近x的位置)
int u = root;
if(!u) return;//不存在节点,无法查找排名
while(t[u].son[x > t[u].val] && x != t[u].val) //找到x所在的位置
u = t[u].son[x > t[u].val];
splay(u, 0);
}
int Next(int x, int f) { //查找前驱/后继
Find(x); //查找x的位置(Splay操作到根节点)
int u = root;
if((t[u].val > x && f) || (t[u].val < x && !f)) return u; //返回结果
u = t[u].son[f];
while(t[u].son[f^1]) u = t[u].son[f^1];
return u;
}
void Delete(int x) { //删除x
int last = Next(x, 0); //查找前驱
int next = Next(x, 1); //查找后继
splay(last, 0); splay(next, last);
int del = t[next].son[0];
if(t[del].cnt > 1) {
t[del].cnt--; //存在多个这个数字,直接减去一个
splay(del, 0);
}
else t[next].son[0] = 0; //清除掉节点
}
int K_th(int x) { //查找排名为x的值
int u = root;
if(t[u].scnt < x) //不存在这么多个数
return -1;
while(1) {
int y = t[u].son[0];
if(x > t[y].scnt + t[u].cnt) { //在排名在u的后面
x -= t[y].scnt + t[u].cnt; //直接减掉这么多
u = t[u].son[1]; //在右子树中继续找
}
else if(t[y].scnt >= x) //如果y的节点数多于x
u = y; //在左子树中继续查找
else return t[u].val;//否则找到了结果,直接返回
}
}
void solve() {
Insert(-inf); Insert(inf);
// 这样的话就可以保证前驱和后继一定能找得到, 不过后面注意计数的变化.
int n; scanf("%d", &n);
while(n--) {
int op, x; scanf("%d%d", &op, &x);
if(op == 1) Insert(x);
else if(op == 2) Delete(x);
else if (op == 3) {
Find(x); printf("%d\n", t[t[root].son[0]].scnt);
}
else if (op == 4) printf("%d\n", K_th(x+1));
else if (op == 5) printf("%d\n", t[Next(x, 0)].val);
else printf("%d\n", t[Next(x, 1)].val);
}
}