重量平衡树

后缀平衡树可以支持前端加字符,以平衡树的形式维护后缀的排名,\(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 ;
		}
	}
}
posted @ 2020-12-18 21:37  JiaZP  阅读(206)  评论(0编辑  收藏  举报