• sam和lct维护一类字符串问题


    洛谷P6292 区间本质不同子串个数

    解题思路

    简单卸卸,将询问离线下来,像HH的项链一样对于每一个子串记录其出现的最右位置,通过后缀自动机可以将过多的子串压起来,但暴力修改颜色肯定不行,用 lct 像树点涂色一样维护即可

    代码

    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template<typename F>
    inline void write(F x)
    {
    	static short st[30];short tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
    	putchar('
    ');
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y); }
    
    const int N = 600500;
    int fa[N], len[N], pos[N];
    int ch[N][26], cnt = 1, las = 1;
    int add(int c) {
    	int p = las, np = las = ++cnt;
    	len[np] = len[p] + 1;
    	for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
    	if (!p) return fa[np] = 1, np;
    	int q = ch[p][c];
    	if (len[q] == len[p] + 1) return fa[np] = q, np;
    	int nq = ++cnt; fa[nq] = fa[q];
    	memcpy(ch[nq], ch[q], sizeof(ch[q]));
    	fa[q] = fa[np] = nq, len[nq] = len[p] + 1;
    	for (; ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
    	return np;
    }
    
    ll d1[N], d2[N], m, n;
    void add(int x, ll v1, ll v2) {
    	for (; x <= n; x += x & -x) 
    		d1[x] += v1, d2[x] += v2;
    }
    
    ll query(int x) {
    	ll r1 = 0, r2 = 0;
    	for (int t = x; t; t -= t & -t)
    		r1 += d1[t], r2 += d2[t];
    	return r1 * (x + 1) - r2;
    }
    
    void add(int l, int r, ll d) { add(l, d, d * l), add(r + 1, -d, -d * (r + 1)); }
    ll query(int l, int r) { return query(r) - query(l - 1); }
    
    struct LCT {
    	#define ls son[x][0]
    	#define rs son[x][1]
    	int son[N][2], f[N], tag[N];
    	bool nroot(int x) {
    		return son[f[x]][0] == x || son[f[x]][1] == x; 
    	}
    	void rotate(int x) {
    		int y = f[x], z = f[y];
    		int k = son[y][1] == x, w = son[x][!k];
    		if (nroot(y)) son[z][son[z][1]==y] = x; f[x] = z;
    		if (w) f[w] = y; son[y][k] = w;
    		f[y] = x, son[x][!k] = y;
    	}
    	
    	void spread(int x) {
    		if (!tag[x]) return;
    		tag[ls] = tag[rs] = tag[x];
    //		tag[x] = 0;
    	}
    	
    	int st[N];
    	void splay(int x) {
    		int y = x, z = 0; st[++z] = y;
    		while (nroot(y)) st[++z] = y = f[y];
    		while (z) spread(st[z--]); 
    		while (nroot(x)) {
    			y = f[x], z = f[y];
    			if (nroot(y)) {
    				if ((son[y][0] == x) ^ (son[z][0] == y)) 
    					rotate(x);
    				else rotate(y);
    			}
    			rotate(x);
    		}
    	}
    	void access(int x, int tg) {
    		int y = 0;
    		for (y = 0; x; x = f[y = x]) {
    			splay(x); rs = y;
    			if (tag[x]) {
    				add(tag[x] - len[x] + 1, tag[x] - len[f[x]], -1), tag[x] = tg;
    //				write(x);
    			}
    		}
    		splay(y), tag[y] = tg;
    //		write(y);
    		add(1, tg, 1);
    	}
    }Lct;
    
    ll ans[N];
    vector<pair<int, int> > v[N];
    char s[N];
    int main() {
    	scanf ("%s", s + 1), n = strlen(s + 1);
    	for (int i = 1;i <= n; i++) pos[i] = add(s[i]-'a');
    	for (int i = 2;i <= cnt; i++) Lct.f[i] = fa[i];
    //	for (int i = 1;i <= n; i++) write(pos[i]);
    	read(m);
    	for (int i = 1, l, r;i <= m; i++) 
    		read(l), read(r), v[r].push_back(MP(i, l));
    	for (int i = 1;i <= n; i++) {
    		Lct.access(pos[i], i);
    		for (auto t: v[i])
    			ans[t.fi] = query(t.se, i);
    	}
    //	puts("");
    	for (int i = 1;i <= m; i++) write(ans[i]);
    	return 0;
    }
    

    LOJ6041. 「雅礼集训 2017 Day7」事情的相似度

    解题思路

    题面可以改成“区间最长出现过两个及以上的子串”,见到了也要会做

    和上题一样,好像字符串和区间有关的蛤

    维护一下每个集合的颜色,然后用线段树更新答案即可

  • 相关阅读:
    前台加请求头token,后台接收
    MD5加密工具类
    SpringBoot实现请求拦截(@Aspect切面类和自定义拦截器)
    Swagger2添加统一header-token
    idea + groovy + mybatis 自动生成 Dao、mappings 和 实体类
    JAVA算法编程题50题及答案
    Python 1基础语法一(注释、行与缩进、多行语句、空行和代码组)
    ENVI 安装
    Python之GUI编程(Tkinter))
    Python 0(安装及初步使用+学习资源推荐)
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13127036.html
Copyright © 2020-2023  润新知