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

题意

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

分析

把询问串和树并在一起,然后建立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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值