LibreOJ #6583. 「ICPC World Finals 2019」何以伊名始 AC自动机+fail树

题意

给你一棵树, N N 个节点,每个节点有一个字母,给出Q个询问,询问有多少个节点从下到上能够跟询问串匹配
N 1 0 6 N\leq 10^6

分析

把询问串和树并在一起,然后建立fail树,siz从深度大到深度小合并,询问就询问fail树的某个点的子树siz和就好了

代码

#include <bits/stdc++.h>

#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define PB push_back
#define CL clear
//#define int long long
#define fi first
#define se second
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef pair<int,int> pii;
const int N = 2e6+10;
const int inf = 1e9;
const int mod = 1e9+7;
inline int rd() {
  char ch = getchar(); int p = 0; int f = 1;
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

struct Tire{
  int son[N][27],fail[N],siz[N],R[N],step[N],px[N];
  queue<int> q;
  int rt,tot;
  void init(){memset(son,0,sizeof(son)); memset(step,0,sizeof(step)); memset(fail,0,sizeof(fail)); rt = tot = 0;}
  int ins(int f,char ch,int sz) {
    int nx = ch - 'A' + 1;
		if(!son[f][nx]){son[f][nx] = ++tot;}
		int u = son[f][nx];
		step[u] = step[f] + 1; siz[u] += sz;
		return u;
	}
	void AC_Tire() {
	  while(!q.empty()) q.pop(); q.push(0);
	  while(!q.empty()) {
	    int u = q.front(); q.pop();
	    for(int i=1;i<=26;++i) {
	      if(!son[u][i]) {
	        if(u==rt) son[u][i] = 0;
					else son[u][i] = son[fail[u]][i];
				}
				else {
				  if(u==rt) fail[son[u][i]] = 0;
				  else fail[son[u][i]] = son[fail[u]][i];
				  q.push(son[u][i]);
				}
			}
		}
	}
	void calc() {
	  for(int i=1;i<=tot;++i) R[step[i]] ++;
	  for(int i=1;i<=tot;++i) R[i] += R[i-1];
	  for(int i=tot;i>=1;--i) px[R[step[i]]--] = i;
	  for(int i=tot;i>=1;--i) {
	    siz[fail[px[i]]] += siz[px[i]];
		}
	}
}tire;

char s[N]; int pos[N];

signed main() {
	int n = rd(); int k = rd(); tire.init();
	rep(i,1,n) {
	  char ch; scanf("\n%c",&ch);
	  int f = rd();
	  tire.ins(f,ch,1);
	}
	rep(i,1,k) {
	  scanf("%s",s+1); int len = strlen(s+1); reverse(s+1,s+len+1);
	  int f = 0; rep(j,1,len) {
	    f=tire.ins(f,s[j],0);
		}pos[i] = f;
	}
	tire.AC_Tire();
	tire.calc();
//	for(int i=1;i<=tire.tot;i++) printf("%lld ",tire.siz[i]);
	rep(i,1,k){
	  printf("%d\n",tire.siz[pos[i]]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/107450206