洛谷 P2414 [NOI2011] 阿狸的打字机

原题链接

给定若干个单词和若干个询问,每次询问求单词\(x\)在单词\(y\)中出现了几次。

考虑用trie存储这些单词,并求出每个节点的fail指针,求单词\(x\)在单词\(y\)中出现的次数,即统计单词\(y\)有几个前缀的fail直接或间接地指向x,即统计\(x\)在fail树上的关于\(y\)的子树和,因为子树的dfs序是连续的,可以用树状数组维护。
如果每个询问都跑一遍\(y\)的后缀肯定超时。发现\(y\)在原本的trie上是一条链,只要将所有的询问离线并按照\(y\)排序,dfs一遍,进入的时候打上标记(+1),回溯的时候清除标记(-1),遇到单词结尾统计\(x\)的子树和即可。

如果\(x\)\(y\)相等,相当于只统计fail树上的当前节点(没有子树)

#include<bits/stdc++.h>
using namespace std;

#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0);

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<int, PII> PPI;
typedef unsigned long long ULL;

const int INF = 0X3f3f3f3f, N = 1e6 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);

int n, idx;

int mp[N], dfn[N], low[N], ql[N], qr[N], Tr[N], ans[N];

vector<int> g[N];

int head[N], tot;

struct EGDE {
	int to, next;
} eg[N << 1];

void add_edge(int x, int y) {
	eg[tot].to = y;
	eg[tot].next = head[x];
	head[x] = tot++;
}

struct Trie {
	int son[26];
	int Son[26];
	int fa;
	int end;
	int fail;
} tr[N];

struct QUES {
	int x, y, id, res;
}ques[N];

int lowbit(int x){
    return x & -x;
}

void modify(int x, int c){
    for(int i = x; i <= N; i += lowbit(i)) Tr[i] += c;
}

int query(int x){
    int res = 0;
    for(int i = x; i >= 1; i -= lowbit(i)) res += Tr[i];
    return res;
}

bool cmp(QUES &a, QUES &b) {
	return a.y < b.y;
}

void get_fail() {
	queue<int> Q;
	rep (i, 0, 25) if (tr[0].son[i]) Q.push(tr[0].son[i]);

	while (!Q.empty()) {
		int u = Q.front();
		Q.pop();
		rep (i, 0, 25) {
			int v = tr[u].son[i];
			if (!v) tr[u].son[i] = tr[tr[u].fail].son[i];
			else tr[v].fail = tr[tr[u].fail].son[i], Q.push(v);
		}
	}
}

void dfs_1(int u) {
	dfn[u] = ++idx;
	rep (i, 0, g[u].size() - 1) dfs_1(g[u][i]);
	low[u] = idx;
}

void dfs_2(int u) {
	modify(dfn[u], 1);
	
	if (tr[u].end) {
		rep (i, ql[tr[u].end], qr[tr[u].end]) {
			int p = mp[ques[i].x];
			ques[i].res = query(low[p]) - query(dfn[p] - 1);
		}
	}
	
	rep (i, 0, 25) if (tr[u].Son[i]) dfs_2(tr[u].Son[i]);
	 
	modify(dfn[u], -1);
} 

void work() {
	memset(head, -1, sizeof head);
	int m;
	string str;
	
	cin >> str >> m;
	
	int u = 0;
	rep (i, 0, str.length() - 1) {
		char c = str[i];
		if (c == 'B') u = tr[u].fa;
		else if (c == 'P') mp[++n] = u, tr[u].end = n;
		else {
			if (tr[u].son[c - 'a']) u = tr[u].son[c - 'a'];
			else idx++, tr[u].son[c - 'a'] = idx, tr[idx].fa = u, u = idx;
		}
	}
	
	rep (i, 0, idx) rep (j, 0, 25) tr[i].Son[j] = tr[i].son[j]; 
	get_fail();
	rep (i, 1, idx) g[tr[i].fail].push_back(i);

	idx = 0, dfs_1(0);
	
	rep (i, 1, m) {
		cin >> ques[i].x >> ques[i].y;
		ques[i].id = i;
	}
	sort(ques + 1, ques + m + 1, cmp);
	
	for (int i = 1, pos = 1; i <= m; i = pos) {
		while (pos <= m && ques[i].y == ques[pos].y) pos++;
		ql[ques[i].y] = i, qr[ques[i].y] = pos - 1;
	}
	
	dfs_2(0);
	
	rep (i, 1, m) ans[ques[i].id] = ques[i].res;
	rep (i, 1, m) cout << ans[i] << endl;
}

signed main() {
	IO

	int test = 1;

	while (test--) {
		work();
	}

	return 0;
}
posted @ 2022-10-12 14:18  xhy666  阅读(44)  评论(0)    收藏  举报