CF547E Mike and Friends (AC automaton)

CF547E Mike and Friends (AC automaton + binary grouping)

Subject

Given \ (n \) strings \ (s_ {1 \ dots n} \) .
\ (q \) times asked how many times \ (s_k \) appeared in \ (s_ {l \ dots r} \) .
\ (n, \ sum | s | \ le 2 \ times 10 ^ 5 \) , \ (q \ le 5 \ times 10 ^ 5 \) .

answer

The essence of the AC automaton fail pointer is to find out the string formed from the root to the current node. The longest prefix makes it equal to its suffix of the same length.

How to judge whether a string T contains another string S? It is easy to know that S must be the suffix of a prefix of T. In my opinion, the termination node of a prefix of T always jumps up the fail pointer, and it can definitely jump to S. The nodes you reach can be simulated by yourself

If this is the case, the question should suddenly be off-line, and the AC automaton should be built to take all the strings and find the dfs order. Add a string to make the prefix node +1, and look at the weight of the subtree.

code show as below:

#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
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>
void write(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int N = 505000;
char tmp[N];
int f[N], fa[N], tot, n, Q;
int ch[N][26], en[N];
int siz[N], dfn[N], num;

int add_c(char *s, int len) {
	int p = 0;
	for (int i = 0;i < len; i++) {
		int di = s[i] - 'a';
		if (!ch[p][di]) fa[ch[p][di] = ++tot] = p;
		p = ch[p][di];
	}
	return p;
}

int h[N], ne[N], to[N], et;
inline void add_e(int x, int y) {
	ne[++et] = h[x], to[h[x] = et] = y;
}

queue<int> q;
void work(void) {
	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];
		}
	}
}

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]];
}

int d[N];
void Add(int x, int k) {
	for (; x <= tot+1; x += x & -x) d[x] += k;
}

ll sum(int x) {
	ll tmp = 0;
	for (; x; x -= x & -x) tmp += d[x];
	return tmp;
}

struct node {
	int k, num, f;
};
vector<node > ask[N];

ll ans[N];
int main() {
	read(n), read(Q);
	for (int i = 1;i <= n; i++) {
		scanf ("%s", tmp);
		en[i] = add_c(tmp, strlen(tmp));
	} work(); dfs(0);
	for (int i = 1;i <= Q; i++) {
		int l, r, x; read(l), read(r), read(x);
		ask[l-1].push_back((node){x, i, -1});
		ask[r].push_back((node){x, i, 1});
	}
	for (int i = 1;i <= n; i++) {
		int x = en[i];
		while (x) Add(dfn[x], 1), x = fa[x];
		for (auto j: ask[i]) {
			int k = en[j.k];
			ans[j.num] += j.f * (sum(dfn[k] + siz[k] - 1) - sum(dfn[k] - 1));
		}
	}
	for (int i = 1;i <= Q; i++) printf ("%lld\n", ans[i]);
}

Guess you like

Origin www.cnblogs.com/Hs-black/p/12672461.html