重量平衡树
后缀平衡树可以支持前端加字符,以平衡树的形式维护后缀的排名,\(O(1)\) 查询两后缀的大小关系。
对于每个后缀,维护一个值域区间 \(l,r\),其权值为平均 \(m=(l+r)/2\),左右儿子的值域区间为 \((l,m),(m,r)\),排名可以通过权值来比较。由于是在前端加字符,每次只会增加一个后缀。这个后缀与其它后缀的比较可以通过一下方式进行:
- 如果第一个字符不同,那么可以 \(O(1)\) 判断出来
- 否则,删掉第一个字符,发现现在的两个字符串都是之前出现过的后缀,直接通过权值 \(O(1)\) 比较即可。
由于深度过深会导致权值精度不足,这里的平衡树需要用保证深度不要太深,需要使用重量平衡树。一般使用替罪羊树。
复杂度:\(O(n \log n)\)
模板:Phorni
几乎完全一致的板子(外层需要套一个线段树)
(假)模板:后缀平衡树
是个假的,没错。体验极差。
但是不管怎么说也用到了后缀平衡树。
模板(调试用)
namespace SGT {
struct node {
double l, r, v;
int fa, son[2], siz;
node(){ l = r = v = 0; fa = son[0] = son[1] = 0; }//BUG
}nd[N];
int ttot, root;
#define ls(x) nd[(x)].son[0]
#define rs(x) nd[(x)].son[1]
#define siz(x) nd[(x)].siz
#define l(x) nd[(x)].l
#define r(x) nd[(x)].r
#define v(x) nd[(x)].v
#define fa(x) nd[(x)].fa
double alpha = 0.75;
inline bool check_rebuild(int cur) {
return siz(ls(cur)) > alpha * siz(cur) || siz(rs(cur)) > alpha * siz(cur);
}
inline void pushup(int cur) {
siz(cur) = siz(ls(cur)) + siz(rs(cur)) + 1;
}
bool cmp(int p, int q) {
return v(p) < v(q);
}
inline bool cmpare(int p, int q) {
return s[p] ^ s[q] ? s[p] < s[q] : cmp(p - 1, q - 1);
}
int h[N], htot;
void dfs_del(int cur) {
if (!cur) return ;
dfs_del(ls(cur));
h[++htot] = cur;
dfs_del(rs(cur));
}
void rebuild(int L, int R, int dir, int faa) {
if (L > R) return ;
int mid = (L + R) >> 1, cur= h[mid];
ls(cur) = rs(cur) = fa(cur) = 0;
if (faa) {
fa(cur) = faa;
if (dir == 0) {
l(cur) = l(faa), r(cur) = v(faa), v(cur) = (l(cur) + r(cur)) / 2.0;
} else {
r(cur) = r(faa), l(cur) = v(faa), v(cur) = (l(cur) + r(cur)) / 2.0;
}
nd[faa].son[dir] = cur;
} else l(cur) = 0, r(cur) = 1e9, v(cur) = (l(cur) + r(cur)) / 2.0, root = cur;
rebuild(L, mid - 1, 0, cur);
rebuild(mid + 1, R, 1, cur);
pushup(cur);
}
inline void ins(int pos, int c) {
++ttot; siz(ttot) = 1;
if (ttot == 1) return l(1) = 0, r(1) = 1e9, v(1) = (r(1) + l(1)) / 2.0, root = ttot, void();
int p = root, lstp = 0, pia = 0;
while (p) {
++siz(p);
if (!pia && check_rebuild(lstp)) pia = lstp;
lstp = p;
if (cmpare(pos, p)) p = ls(p);
else p = rs(p);
}
p = lstp;
fa(ttot) = p;
if (cmpare(pos, p)) {
ls(p) = ttot;
l(ttot) = l(p); r(ttot) = v(p); v(ttot) = (l(ttot) + r(ttot)) / 2.0;
} else {
rs(p) = ttot;
r(ttot) = r(p), l(ttot) = v(p), v(ttot) = (l(ttot) + r(ttot)) / 2.0;
}
if (pia) {
htot = 0;
dfs_del(pia);
rebuild(1, htot, cmp(pia, fa(pia)) ^ 1, fa(pia));
return ;
}
}
}