将所有字符串哈希后存入哈希表,合并或分裂时暴力更新。
这样复杂度看上去是
O(nk2)
O
(
n
k
2
)
的,实际上是
O(ck2+nk)
O
(
c
k
2
+
n
k
)
。
证明:
显然要使复杂度更大,合并的
2
2
个队列的长度一定是 的
假如使合并的队列长度为
S
S
,这样的队列只有 个,复杂度为
nSS2=nS
n
S
S
2
=
n
S
,当
S=k
S
=
k
时取最大值。
一次分裂最多会使复杂度增加
2k2
2
k
2
,所以分裂的复杂度为
O(ck2)
O
(
c
k
2
)
。
总复杂度为
O(ck2+nk)
O
(
c
k
2
+
n
k
)
。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int SIZE=1<<25;
inline char nc(){
static char buf[SIZE],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int& x){
char c=nc();
for(;c<'0'||c>'9';c=nc());
for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
char ss[30];
int Len;
inline void Print(int x){
if(!x){
putchar('0');
putchar('\n');
return;
}
for(Len=0;x;x/=10)ss[++Len]=x%10;
while(Len)putchar(ss[Len--]+48);
putchar('\n');
}
typedef unsigned long long ll;
const int D=131072-1;
const int T=10000000;
const int N=500010;
const int M=998244353;
const ll P=1000000007;
int g[N],len;
int c[N];
int k,n,m,x,y;
int nx[N],ls[N];
ll p[51];
struct Hash_Table{
int s[D<<2],nx[D<<2],h[D+1],cnt;
ll a[D<<2];
inline void Add(ll x){
int y=x&D;
for(int i=h[y];i;i=nx[i])
if(a[i]==x){
s[i]++;
return;
}
a[++cnt]=x;nx[cnt]=h[y];h[y]=cnt;s[cnt]=1;
}
inline void Erase(ll x){
for(int i=h[x&D];i;i=nx[i])
if(a[i]==x){
s[i]--;
return;
}
}
inline int Query(ll x){
for(int i=h[x&D];i;i=nx[i])
if(a[i]==x)return s[i];
return 0;
}
}Hash[51];
inline void Get(){
len=0;
char c=nc();
for(;c<'0'||c>'9';c=nc());
for(;c>='0'&&c<='9';c=nc())g[++len]=c-'0';
}
inline void Update1(int x,int y){
ll S=0,s;
for(int j=1,Y=y;Y&&j<50;j++,Y=nx[Y]){
S=S*P+c[Y];s=S;
for(int i=1,X=x;X&&i+j<=50;i++,X=ls[X])
s+=p[i+j-1]*c[X],Hash[i+j].Add(s);
}
nx[x]=y;ls[y]=x;
}
inline void Update2(int x,int y){
ll S=0,s;
for(int j=1,Y=y;Y&&j<50;j++,Y=nx[Y]){
S=S*P+c[Y];s=S;
for(int i=1,X=x;X&&i+j<=50;i++,X=ls[X])
s+=p[i+j-1]*c[X],Hash[i+j].Erase(s);
}
ls[y]=nx[x]=0;
}
int main(){
Read(n);Read(m);
for(int i=1;i<=n;i++)Read(c[i]),Hash[1].Add(c[i]);
p[0]=1;
for(int i=1;i<=50;i++)p[i]=p[i-1]*P;
for(int i=1;i<=m;i++){
Read(k);
if(k==1)Read(x),Read(y),Update1(x,y);else
if(k==2)Read(x),Update2(x,nx[x]);else{
Get();Read(k);
ll s=0,t=p[k];int Res=1;
for(int j=1;j<k;j++)s=s*P+g[j];
for(int j=k;j<=len;j++){
s=s*P+g[j]-t*g[j-k];
Res=1ll*Res*Hash[k].Query(s)%M;
}
Print(Res);
}
}
return 0;
}