蒟蒻求调

P3369 【模板】普通平衡树

两个问题: 一是 `delete` 函数有点问题,我改了一下: ```c++ inline void delect(int val){ int p = rt; while(1){ if(val == value[p]) break; if(val < value[p]) p = sons[p][0]; else p = sons[p][1]; } if(cnt[p] > 1){ cnt[p]--; sz[p]--; splay(p); return; } while(1){ if(!sons[p][0] && !sons[p][1]){ sons[fa[p]][get_pos(p)] = 0; update(fa[p]); if(fa[p]) splay(fa[p]); else rt=0; fa[p] = 0; return ; } if(tem = sons[p][0]){ rorate(sons[p][0]); p = sons[tem][1]; } else{ rorate(tem = sons[p][1]); p = sons[tem][0]; } } } ``` 二是 `get_rk` 所访问到的点要 splay 上去,否则复杂度会退化。 当然可能还有点问题,毕竟我到现在都不能保证我的 splay 板子复杂度是对的... @[huangrenheluogu](/user/461359)
by xzf888 @ 2023-12-12 15:48:58


@[xzf888](/user/1217150) 谢谢,但是问个问题,我感觉 `get_rk` 的函数就是一个访问的过程,不需要 Splay 吧。
by huangrenheluogu @ 2023-12-12 16:35:10


`delect` 函数已更改,下面重发一遍代码: ```cpp #include<bits/stdc++.h> using namespace std; const int N = 2e5 + 5; int n, sons[N][2], cnt[N], idx, rt, fa[N], sz[N], value[N], tem, o, val; inline bool get_pos(int x){ return x == sons[fa[x]][1]; } inline void update(int x){ sz[x] = sz[sons[x][0]] + sz[sons[x][1]] + cnt[x]; } inline void rorate(int x){ int f = fa[x], gf = fa[fa[x]]; if(f == 0) return ; bool pos = get_pos(x), pos1 = get_pos(f); sons[f][pos] = sons[x][pos ^ 1]; sons[x][pos ^ 1] = f; fa[f] = x, fa[sons[f][pos]] = f; fa[x] = gf; if(gf){ sons[gf][pos1] = x; } update(f); update(x); } inline void splay(int x){ for(int i = fa[x]; i ; rorate(x), i = fa[x]){ if(fa[i]) rorate(get_pos(i) == get_pos(x) ? i : x); } rt = x; } inline void insert(int val){ int p = rt, f = 0; while(1){ if(val == value[p] && p){ cnt[p]++; sz[p]++; splay(p); return ; } f = p; p = sons[p][val < value[p] ? 0 : 1]; if(!p){ p = ++idx; cnt[p] = 1; sz[p] = 1; value[p] = val; if(f){ fa[p] = f; sons[f][value[f] > val ? 0 : 1] = p; update(f); } splay(p); return ; } } } inline void delect(int val){ int p = rt; while(1){ if(val == value[p]) break; if(val < value[p]) p = sons[p][0]; else p = sons[p][1]; } if(cnt[p] > 1){ cnt[p]--; sz[p]--; splay(p); } while(1){ if(!sons[p][0] && !sons[p][1]){ sons[fa[p]][get_pos(p)] = 0; update(fa[p]); if(fa[p]) splay(fa[p]); else rt = 0; fa[p] = 0; return ; } if(tem = sons[p][0]){ rorate(sons[p][0]); p = sons[tem][1]; } else{ rorate(tem = sons[p][1]); p = sons[tem][0]; } } } inline int get_rk(int val){ int p = rt, res = 0; while(1){ if(!p){ return res + 1; } if(val == value[p]){ return res + sz[sons[p][0]] + 1; } if(val < value[p]){ p = sons[p][0]; } else{ res += sz[sons[p][0]] + cnt[p]; p = sons[p][1]; } } } inline int get_num(int rk){ int p = rt; while(1){ if(rk <= sz[sons[p][0]]){ p = sons[p][0]; continue ; } if(rk > sz[sons[p][0]] + cnt[p]){ rk -= sz[sons[p][0]] + cnt[p]; p = sons[p][1]; continue ; } return value[p]; } } inline int get_pre(){ int p = sons[rt][0]; while(sons[p][1]) p = sons[p][1]; return value[p]; } inline int get_nxt(){ int p = sons[rt][1]; while(sons[p][0]) p = sons[p][0]; return value[p]; } int main(){ // freopen("data.in", "r", stdin); // freopen("code.out", "w", stdout); scanf("%d", &n); while(n--){ scanf("%d%d", &o, &val); // printf("opt is %d %d : \n", o, val); switch(o){ case 1: insert(val); break; case 2: delect(val); break; case 3: printf("%d\n", get_rk(val)); break; case 4: printf("%d\n", get_num(val)); break; case 5: insert(val); printf("%d\n", get_pre()); delect(val); break; case 6: insert(val); printf("%d\n", get_nxt()); delect(val); break; default: assert(0); } } return 0; } ```
by huangrenheluogu @ 2023-12-12 16:38:00


@[huangrenheluogu](/user/461359) 你的delete真改完了吗?好像在67行后面还少了 `return` 吧 另外最后一个点好像是从小到大插入权值的,这时候 splay 会退化为接近一条链,此时在多次查询最深的一号点的排名会炸。 毕竟 splay 嘛... 我用了半年的板子最后发现写了个假的双旋...
by xzf888 @ 2023-12-12 21:43:00


@[xzf888](/user/1217150) 谢谢。
by huangrenheluogu @ 2023-12-12 21:45:12


已 A,结此贴。
by huangrenheluogu @ 2023-12-13 07:51:24


|