zoukankan      html  css  js  c++  java
  • 重量平衡树

    后缀平衡树可以支持前端加字符,以平衡树的形式维护后缀的排名,(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 ;
    		}
    	}
    }
    
  • 相关阅读:
    pycharm中使用redis模块入门
    ubuntu sudo apt-get update与sudo apt-get upgrade的作用及区别,以及python pip的安装
    pycharm修改快捷键
    python2.7.5安装docker-compose的方法
    (二)影响持续交付的因素
    (一)持续交付的定义与价值
    CentOS6的/etc/rc.local不执行的问题解决
    Redis集群进阶之路
    好文收集(长期更新)
    MongoDB如何释放空闲空间?
  • 原文地址:https://www.cnblogs.com/JiaZP/p/14157211.html
Copyright © 2011-2022 走看看