[bzoj2746][HEOI2012]旅行问题 _AC自动机_倍增

[HEOI2012]旅行问题

题目链接https://www.lydsy.com/JudgeOnline/problem.php?id=2746


题解

这个是讲课时候的题。

讲课的时候都在想怎么后缀自动机....

当然是能做啦,$SAM$这么强。

实际上是个$AC$自动机,按照题目模拟就行了。

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1 << 20 ;

const int mod = 1000000007 ;

const int P = 21 ;

queue <int> Q;

int n, m, ch[N][26], fail[N][25], dep[N], tail, cnt, pos[N << 1], lenth[N];

char str[N];

ll Hash[N];

void insert() {
	int len = strlen(str);
	int p = 0;
	for (int i = 0; i < len; i ++ ) {
		int c = str[i] - 'a';
		if (!ch[p][c]) {
			ch[p][c] = ++tail;
			Hash[ch[p][c]] = (((Hash[p] * 26) % mod) + c) % mod;
		}
		pos[ ++ cnt] = ch[p][c]; 
		p = ch[p][c];
	}   
}

void getfail() {
	dep[0] = 0;
	for (int i = 0; i < 26; i ++ ) {
		if (ch[0][i]) {
			fail[ch[0][i]][0] = 0;
			dep[ch[0][i]] = 1;
			Q.push(ch[0][i]);
		}
	}
	while (!Q.empty()) {
		int top = Q.front();
		Q.pop();
		for (int i = 0; i < 26; i ++ ) {
			if (!ch[top][i]) {
				ch[top][i] = ch[fail[top][0]][i];
				continue;
			}
			int u = ch[top][i];
			fail[u][0] = ch[fail[top][0]][i];
			dep[u] = dep[fail[u][0]] + 1;
			for (int j = 1; j < P; j ++ ) {
				fail[u][j] = fail[fail[u][j - 1]][j - 1];
			}
			Q.push(u);
		}
	}   
}

int getlca(int u, int v) {
	if (dep[u] < dep[v]) {
		swap(u, v);
	}
	int d = dep[u] - dep[v];
	for (int i = 0; d; d >>= 1, i ++ ) {
		if (d & 1) {
			u = fail[u][i];
		}
	}
	if (u == v) {
		return u;
	}
	for (int p = P - 1; p >= 0; p -- ) {
		if (fail[u][p] != fail[v][p]) {
			u = fail[u][p];
			v = fail[v][p];   
		}
	}   
	return fail[u][0];
}

int main() {
	scanf("%d", &n);
	memset(fail, 0, sizeof fail);
	lenth[0] = 0;
	for (int i = 1; i <= n; i ++ ) {
		scanf("%s", str);
		insert();
		lenth[i] = strlen(str);
		lenth[i] += lenth[i - 1];
	}
	getfail();
	scanf("%d", &m);
	while (m -- ) {
		int p1, l1, p2, l2;
		scanf("%d%d%d%d", &p1, &l1, &p2, &l2);
		int t1 = pos[lenth[p1 - 1] + l1];
		int t2 = pos[lenth[p2 - 1] + l2];
		int lca = getlca(t1, t2);
		printf("%lld\n", Hash[lca]);
	}
	return 0;
}

小结:注意一下AC自动机找LCA要倍增,别直接跳fail......

posted @ 2019-08-27 22:09  JZYshuraK_彧  阅读(139)  评论(0编辑  收藏  举报