• bzoj5084 hashit 广义SAM+树链的并


    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=5084

    题解

    考虑平常对于静态问题,我们应该如何用 SAM 求本质不同的子串个数。

    对于一个常规的 SAM,这个东西应该是 (sumlimits_{iin V} len_i - len_{fa_i})

    很容易发现,我们如果把这个字符串每一个时刻的前一个字符和后一个字符给连接起来,这是一个树的关系。

    考虑对这个树建立一棵广义 SAM。

    但是上面的结论在广义 SAM 中不适用。不适用的是 (i) 的条件。

    如果固定了当前的串是树上的哪一条链,这里就不应该是 (i in V) 了,而是 (i) 代表的子串(等价类)在这个串中出现过。

    这个东西显然就是对于这个串,每一个前缀所在的 (endpos) 集合的等价类的点在 parent 树上的链的并的长度了。

    因为每一次的添加或删除字符影响的只有一个点,所以维护 (parent) 树上的树链的并来实现。


    时间复杂度 (O(nlog n))

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 2e5 + 7;
    
    int n, Q, nod, dfc;
    ll ans = 0;
    char s[N], v[N];
    int id[N], fa[N], ip[N], dis[N];
    int f[N], dep[N], siz[N], son[N], dfn[N], pre[N], top[N];
    
    struct Edge { int to, ne, w; } g[N]; int head[N], tot;
    inline void addedge(int x, int y, int z) { g[++tot].to = y, g[tot].w = z, g[tot].ne = head[x], head[x] = tot; }
    inline void adde(int x, int y, int z) { addedge(x, y, z), addedge(y, x, z); }
    
    struct Node { int c[26], fa, len; } t[N];
    inline int extend(int p, int x) {
    	if (t[p].c[x]) {
    		int q = t[p].c[x];
    		if (t[q].len == t[p].len + 1) return q;
    		int nq = ++nod;
    		t[nq] = t[q], t[nq].len = t[p].len + 1, t[q].fa = nq;
    		for (; t[p].c[x] == q; p = t[p].fa) t[p].c[x] = nq;
    		return nq;
    	}
    	int np = ++nod;
    	t[np].len = t[p].len + 1;
    	for (; p && !t[p].c[x]; p = t[p].fa) t[p].c[x] = np;
    	// dbg("p = %d, np = %d, nod = %d, x = %c
    ", p, np, nod, x);
    	if (!p) t[np].fa = 1;
    	else {
    		int q = t[p].c[x];
    		if (t[q].len == t[p].len + 1) t[np].fa = q;
    		else {
    			int nq = ++nod;
    			t[nq] = t[q], t[nq].len = t[p].len + 1, t[q].fa = t[np].fa = nq;
    			for (; p && t[p].c[x] == q; p = t[p].fa) t[p].c[x] = nq;
    		}
    	}
    	// dbg("p = %d, np = %d, nod = %d, x = %c
    ", p, np, nod, x);
    	assert(!t[1].fa);
    	return np;
    }
    
    inline void dfs1(int x, int fa = 0) {
    	f[x] = fa, dep[x] = dep[fa] + 1, siz[x] = 1;
    	for fec(i, x, y) if (y != fa) dfs1(y, x), siz[x] += siz[y], siz[y] > siz[son[x]] && (son[x] = y);
    }
    inline void dfs2(int x, int pa) {
    	top[x] = pa, dfn[x] = ++dfc, pre[dfc] = x;
    	if (!son[x]) return; dfs2(son[x], pa);
    	for fec(i, x, y) if (y != f[x] && y != son[x]) dfs2(y, y);
    }
    inline int lca(int x, int y) {
    	while (top[x] != top[y]) dep[top[x]] > dep[top[y]] ? x = f[top[x]] : y = f[top[y]];
    	return dep[x] < dep[y] ? x : y;
    }
    
    inline void build() {
    	ip[1] = nod = 1;
    	for (int i = 2; i <= n; ++i)
    		ip[i] = extend(ip[fa[i]], v[i] - 'a');
    	for (int i = 2; i <= nod; ++i) addedge(t[i].fa, i, t[i].len - t[t[i].fa].len), dis[i] = t[i].len;
    	// for (int i = 1; i <= nod; ++i) dbg("i = %d, t[i].fa = %d, t[i].len = %d
    ", i, t[i].fa, t[i].len);
    }
    
    struct cmp {
    	inline bool operator () (const int &x, const int &y) { return dfn[x] < dfn[y]; }
    };
    std::set<int, cmp> st;
    
    inline void ins(int x) {
    	std::set<int, cmp>::iterator p = st.lower_bound(x);
    	int y = 0, z = 0;
    	ans += dis[x];
    	if (p != st.end()) y = *p, ans -= dis[lca(x, y)];
    	if (p != st.begin()) z = *--p, ans -= dis[lca(x, z)];
    	if (y && z) ans += dis[lca(y, z)];
    	st.insert(x);
    }
    
    inline void del(int x) {
    	st.erase(x);
    	std::set<int, cmp>::iterator p = st.lower_bound(x);
    	int y = 0, z = 0;
    	ans -= dis[x];
    	if (p != st.end()) y = *p, ans += dis[lca(x, y)];
    	if (p != st.begin()) z = *--p, ans += dis[lca(x, z)];
    	if (y && z) ans -= dis[lca(y, z)];
    }
    
    inline void work() {
    	build();
    	dfs1(1), dfs2(1, 1);
    	int now = 1;
    	for (int i = 1; i <= Q; ++i) {
    		if (s[i] == '-') del(ip[now]), now = fa[now];
    		else now = id[i], ins(ip[now]);
    		// dbg("now = %d, ip = %d
    ", now, ip[now]);
    		printf("%lld
    ", ans);
    	}
    }
    
    inline void init() {
    	scanf("%s", s + 1);
    	Q = strlen(s + 1);
    	int now = n = 1;
    	for (int i = 1; i <= Q; ++i) {
    		if (s[i] == '-') now = fa[now];
    		else fa[++n] = now, v[n] = s[i], now = n;
    		id[i] = now;
    	}
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    结构与算法(04):排序规则与查找算法
    虚拟机系列 | JVM特点,基础结构与执行周期
    Springboot 轻量替代框架 Solon 1.3.10 发布
    Java RPC 框架 Solon 1.3.9 发布,更便利的支持
    Java RPC 框架 Solon 1.3.7 发布,增强Cloud接口能力范围
    分享个本地maven配置
    Java RPC 框架 Solon 1.3.1 发布,推出Cloud接口与配置规范
    使用 quartz-solon-plugin 开发定时任务(新)
    使用 cron4j-solon-plugin 开发定时任务(新)
    国际开源社区OW2成立快应用兴趣小组,助推快应用生态发展
  • 原文地址:https://www.cnblogs.com/hankeke/p/bzoj5084.html
Copyright © 2020-2023  润新知