题目链接 2016 青岛网络赛 Problem C
题意 给出一些敏感词,和一篇文章。现在要屏蔽这篇文章中所有出现过的敏感词,屏蔽掉的用$'*'$表示。
建立$AC$自动机,查询的时候沿着$fail$指针往下走,当匹配成功的时候更新$f[i]$
$f[i]$表示要屏蔽以第$i$个字母结尾的长度为$f[i]$的字符串。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define fi first
#define se second
typedef long long LL;
const int N = 1e6 + 10;
int T, n;
int f[N];
char buf[N];
struct Trie{
int nxt[N][26], fail[N], end[N], len[N];
int root, tot;
int newnode(){
rep(i, 0, 25) nxt[tot][i] = -1;
len[tot] = end[tot] = 0; tot++;
return tot - 1;
}
void init(){
tot = 0;
root = newnode();
}
void ins(char buf[]){
int l = strlen(buf);
int now = root;
rep(i, 0, l - 1){
if (nxt[now][buf[i] - 'a'] == -1) nxt[now][buf[i] - 'a'] = newnode();
now = nxt[now][buf[i] - 'a'];
}
end[now]++;
len[now] = strlen(buf);
}
void build(){
queue <int> q;
fail[root] = root;
rep(i, 0, 25){
if (~nxt[root][i]){
fail[nxt[root][i]] = root;
q.push(nxt[root][i]);
}
else nxt[root][i] = root;
}
while (!q.empty()){
int now = q.front();
q.pop();
rep(i, 0, 25){
if (~nxt[now][i]){
fail[nxt[now][i]] = nxt[fail[now]][i];
q.push(nxt[now][i]);
}
else nxt[now][i] = nxt[fail[now]][i];
}
}
}
void query(char buf[]){
int l = strlen(buf);
int now = root;
int res = 0;
rep(i, 0, l - 1){
int sign;
if (buf[i] >= 'A' && buf[i] <= 'Z') sign = buf[i] - 'A';
else if (buf[i] >= 'a' && buf[i] <= 'z') sign = buf[i] - 'a';
else{
now = root;
continue;
}
now = nxt[now][sign];
int temp = now;
while (temp != root){
f[i] = max(f[i], len[temp]);
temp = fail[temp];
}
}
}
} ac;
int leng, num;
int main(){
scanf("%d",&T);
while (T--){
scanf("%d",&n);
ac.init();
rep(i, 1, n){
scanf("%s", buf);
ac.ins(buf);
}
ac.build();
getchar();
gets(buf);
memset(f, 0, sizeof f);
ac.query(buf);
leng = strlen(buf);
num = 0;
dec(i, leng - 1, 0){
num = max(num, f[i]);
if (num == 0) continue;
else buf[i] = '*', num--;
}
puts(buf);
}
return 0;
}