题解 CF710F【String Set Queries】
这个题应该至少有 *2700 吧/kel
题意
维护一个字符串集合,支持三种操作共 $q$ 次:
- 加入字符串 $s$
- 删除已有字符串 $s$
- 查询集合中的所有字符串在给出的模板串 $s$ 中出现的次数
强制在线。
$q,\sum|s|\le10^6$.
思路
老师要我写题解。
删除是假的,可以看为两个集合分别代表加入和删除,求两个集合的答案差。
考虑询问形式很像 $\text{ACAM}$,如果没有强制在线,直接把所有的加入串拉出来建出 $\text{ACAM}$,加入就是子树加,查询就是在 $\text{Fail}$ 树上这个字符串对应的路径的点权和。
现在强制在线了,但如果我们知道之前所有的操作构成的 $\text{ACAM}$ 和对应的权值便可以简单查询。
考虑建立 $S$ 个 $\text{ACAM}$,当某个 $\text{ACAM}$ 达到某特定大小时不再加入字符串,新开一个 $\text{ACAM}$,否则将次串加入 $\text{ACAM}$ 并重构。每次询问遍历所有 $\text{ACAM}$ 求对应答案。发现每个字符串只会在重构中出现 $O(\dfrac{n}S)$ 次,询问有 $O(S)$ 个 $\text{ACAM}$,令 $S=O(\sqrt n)$ 则复杂度是 $O(n\sqrt n)$,无法达到我的要求。
考虑将大小相同的 $\text{ACAM}$ 合并,每次合并暴力合并 $\text{Trie}$,重建 $\text{Fail}$ 树并计算子树加带来的贡献,加入字符串时直接建立大小为 $1$ 的 $\text{ACAM}$。可以发现,每个 $\text{ACAM}$ 大小为 $2^i$,且 $i$ 互不相同。每个字符串只会合并 $O(\log n)$ 次,同时只会出现 $O(\log n)$ 个 $\text{ACAM}$。时间复杂度为 $O(n\log n)$,可以通过。
一般称这种方法为二进制分组,有时会有强大的作用。
代码(强制在线方法与题目描述不同,仅供参考):
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=1e6+10;
struct ACAM{
int cnt,rts,tr[N][26],tr2[N][26];
int rt[N],fail[N],val[N],siz[N];
int delcnt,del[N];
ll tmp[N];
inline int newnode(){
return delcnt?del[delcnt--]:++cnt;
}
inline void insert(char *s,int &rt){
if(!rt) rt=newnode();
int n=strlen(s+1);
int cur=rt;
for(int i=1;i<=n;i++){
int c=s[i]-'a';
if(!tr[cur][c])
tr[cur][c]=newnode();
cur=tr[cur][c];
}
val[cur]++;
}
inline void makefail(int rt){
queue<int>q;
fail[rt]=rt;
for(int i=0;i<26;i++)
if(tr[rt][i]){
tr2[rt][i]=tr[rt][i];
fail[tr[rt][i]]=rt;
q.push(tr[rt][i]);
}else{
tr2[rt][i]=rt;
}
while(!q.empty()){
int cur=q.front();
q.pop();
tmp[cur]=val[cur]+tmp[fail[cur]];
for(int i=0;i<26;i++)
if(tr[cur][i]){
tr2[cur][i]=tr[cur][i];
fail[tr[cur][i]]=tr2[fail[cur]][i];
q.push(tr[cur][i]);
}else{
tr2[cur][i]=tr2[fail[cur]][i];
}
}
}
inline int merge(int x,int y){
if(!x||!y) return x+y;
val[x]+=val[y];
// tmp[y]=0;
// del[++delcnt]=y;
for(int i=0;i<26;i++)
tr[x][i]=merge(tr[x][i],tr[y][i]);//,tr[y][i]=0;
return x;
}
inline void insert(char *s){
siz[++rts]=1;
insert(s,rt[rts]);
while(siz[rts-1]==siz[rts]){
siz[rts-1]+=siz[rts];
rt[rts-1]=merge(rt[rts-1],rt[rts]);
rt[rts]=0;
rts--;
}
makefail(rt[rts]);
}
inline ll query(char *s){
int n=strlen(s+1);
ll ans=0;
for(int i=1;i<=rts;i++){
int cur=rt[i];
for(int j=1;j<=n;j++){
cur=tr2[cur][s[j]-'a'];
ans+=tmp[cur];
}
}
return ans;
}
}add,del;
int q;
char str[N];
ll last;
/*
6
1 . 25
1 ab 2
3 abcab 2
2 ab 0
1 ab 2
3 ababab 0
*/
int main(){
q=read();
while(q--){
int opt=read();
readstr(str);
int n=strlen(str+1);
if(n==1&&str[1]=='.') n=0;
ll tmp=read()^last;
str[n+1]=tmp+'a',str[n+2]=0;
if(opt==1) add.insert(str);
if(opt==2) del.insert(str);
if(opt==3) write(last=add.query(str)-del.query(str)),putc('\n');
}
flush();
}
再见 qwq~

浙公网安备 33010602011771号