zoukankan      html  css  js  c++  java
  • CF587F Duff is Mad(AC自动机+根号分治)

    CF587F Duff is Mad(AC自动机+根号分治)

    题目大意

    给定 (n) 个字符串 (s_{1 dots n})

    • (q) 次询问 (s_{l dots r})(s_k) 中出现了多少次。
    • (n,q,sum_{i=1}^n |s_i| le 10^5)

    解题思路

    相似的题(s_k)(s_{l dots r}) 中出现了多少次此题其他限制条件 AC自动机的题怎么都一个套路啊

    很容易想到暴力思路, 离线后直接暴力在原trie树上走, 拿树状数组维护一下就行

    很不巧的是(sum|s_k|)并没有保证, 因为一个k可以被询问多次, 因此我们考虑其他做法

    然后我们想如果(|s_k| le sqrt m) m是字符串大小之和, 直接暴力做是可行的, 这样复杂度为(Theta(qlog_q+nsqrt m log_m)), 可以改变阈值获得更优的复杂度, 但这样也可过

    如果(|s_k| ge sqrt m), 代表着这样的串只有(sqrt m)个, 即使对每个串(Theta(n))暴力也可以了, 所以我们将询问挂在(s_k)上, 将它的每个前缀节点标记为1, dfs一遍求子树权值和, 从一到n加入字符串, 直接加上val[end[i]]就是字符串i的贡献

    我的dfs直接写的暴力跳fail, 结果也过了?!

    代码如下:

    #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 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 = 100500;
    vector<char> s[N];
    char res[N];
    int ch[N][26], en[N], dfn[N];
    int f[N], cnt, num, T, m, n;
    int ne[N], to[N], h[N], tot;
    inline void add_e(int x, int y) {
    	ne[++tot] = h[x], to[h[x] = tot] = y;
    }
    
    int add(char *s, int len) {
    	int p = 0;
    	for (int i = 1;i <= len; i++) {
    		int di = s[i] - 'a';
    		if (!ch[p][di]) ch[p][di] = ++cnt;
    		p = ch[p][di];
    	} return p;
    }
    
    void build(void) {
    	queue<int> q;
    	for (int i = 0;i < 26; i++)	
    		if (ch[0][i]) q.push(ch[0][i]);
    	while (q.size()) {
    		int x = q.front(); q.pop();
    		add_e(f[x], x);
    		for (int i = 0;i < 26; i++)
    			if (ch[x][i]) f[ch[x][i]] = ch[f[x]][i], q.push(ch[x][i]);
    			else ch[x][i] = ch[f[x]][i];
    	}
    }
     
    int siz[N];
    void dfs(int x) {
    	dfn[x] = ++num, siz[x] = 1;
    	for (int i = h[x]; i; i = ne[i]) 
    		dfs(to[i]), siz[x] += siz[to[i]];
    }
    
    struct node {
    	int k, l, num;
    	bool operator < (const node &i) const {
    		return l < i.l;
    	}
    };
    
    vector<node> v[N], q; 
    
    ll ans[N], d[N], val[N];
    void Add(int x, int k) {
    	for (; x <= num; x += x & -x) d[x] += k;
    }
    
    ll Sum(int x) {
    	ll res = 0;
    	for (; x ; x -= x & -x) res += d[x];
    	return res;
    }
    
    int main() {
    	read(n), read(m); T = 250;
    	for (int i = 1;i <= n; i++) {
    		scanf ("%s", res + 1); 
    		int t = strlen(res + 1); en[i] = add(res, t);
    		s[i].push_back('f');
    		for (int j = 1;j <= t; j++) s[i].push_back(res[j]);
    	}
    	build(); dfs(0);
    	
    	for (int i = 1;i <= m; i++) {
    		int l, r, k; read(l), read(r), read(k);
    		if ((int)s[k].size() > T) {
    			if (l-1) v[k].push_back((node){-1, l-1, i});
    			v[k].push_back((node){1, r, i});
    		}
    		else {
    			if (l-1) q.push_back((node){-k, l-1, i});
    			q.push_back((node){k, r, i});
    		}
    	}
    	sort(q.begin(), q.end());
    	for (int i = 1;i <= n; i++) {
    		if (!v[i].size()) continue;
    		sort(v[i].begin(), v[i].end());
    		memset(val, 0, sizeof(val));
    		int p = 0;
    		for (int j = 1;j < (int)s[i].size(); j++) {
    			p = ch[p][s[i][j]-'a'];
    			int x = p;
    			while (x) val[x]++, x = f[x];
    		}
    		ll sum = 0, now = 1;
    		for (auto j: v[i]) {
    			while (now <= j.l) 
    				sum += val[en[now++]];
    			ans[j.num] += j.k * sum;
    		}
    	}
    	
    	int now = 1;
    	for (auto i: q) {
    		while (now <= i.l) {
    			int x = en[now];
    			Add(dfn[x] + siz[x], -1);
    			Add(dfn[x], 1); now++; 
    		}
    		int p = 0, f = i.k > 0 ? 1 : -1;
    		if (i.k < 0) i.k = -i.k;
    		ll sum = 0;
    		for (int j = 1;j < (int)s[i.k].size(); j++) {
    			p = ch[p][s[i.k][j]-'a'];
    			sum += Sum(dfn[p]);
    		}
    		ans[i.num] += f * sum;
    	}
    	
    	for (int i = 1;i <= m; i++) printf ("%lld
    ", ans[i]); 
    	
    	return 0;
    }
    
  • 相关阅读:
    最全的常用正则表达式大全--包括校验数字、字符、一些特殊的需求等【转】
    【转】浏览器“后退”、“前进”或可以这么去监听
    vue单页面title修改
    Vue.js中ref ($refs)用法举例总结
    js 程序执行与顺序实现详解
    $(document).ready和window.onload的区别 【转】
    linq to xml(C#)
    TCP/IP|| 建立连接或终止
    TCP/IP TCP
    TCP/IP DNS
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12674747.html
Copyright © 2011-2022 走看看