做法较为明显,直接模拟即可。Hash比较字符串。
复杂度分析一波,如果没有2操作的话,复杂度显然是
O(nk)
O
(
n
k
)
的,考虑有2操作的话,分裂两个蚯蚓的复杂度是
O(k2)
O
(
k
2
)
,因此而带来的合并复杂度也是
O(ck2)
O
(
c
k
2
)
的,因此总的复杂度就是
O(nk+ck2+|s|)
O
(
n
k
+
c
k
2
+
|
s
|
)
然后就是卡常啦!
首先我们离线操作,先把可能会询问到的串的Hash值扔进Hash表,不会被问到的Hash值就不存了,这样可以保证Hash的节点最多
O(|s|)
O
(
|
s
|
)
个
然后就是Hash表玄学技巧啦!因为最多1e7个点,所以分到1e8个桶内比较科学。
不过这样uoj过不去!亲测可过的Hash表模数为10233333~
#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define ll long long
#define inf 0x3f3f3f3f
#define N 200010
#define mod 998244353
#define k1 11113
#define Mod 10233333
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m,nn,a[N],h[Mod],num=0,pre[N],succ[N],now=1;
ull bin[60],b[N][60];
int s[10000010];
inline void get_S(){
char ch=gc();
while(ch<'0'||ch>'9') ch=gc();
while(ch>='0'&&ch<='9') s[now++]=ch-'0',ch=gc();
}
struct Hash_table{
ull key;int val,next;
}data[10000010];
struct quer{
int op,x,y,k;
}qq[500010];
inline void ins1(ull key){
int x=key%Mod;
for(int i=h[x];i;i=data[i].next)
if(data[i].key==key) return;
data[++num].key=key;data[num].val=0;data[num].next=h[x];h[x]=num;
}
inline void ins(ull key,int val){
int x=key%Mod;
for(int i=h[x];i;i=data[i].next)
if(data[i].key==key){data[i].val+=val;return;}
}
inline int hs(ull key){
int x=key%Mod;
for(int i=h[x];i;i=data[i].next)
if(data[i].key==key) return data[i].val;return 0;
}
int main(){
// freopen("queue25.in","r",stdin);
// freopen("a.out","w",stdout);
n=read();m=read();bin[0]=1;
for(int i=1;i<=50;++i) bin[i]=bin[i-1]*k1;
for(int i=1;i<=n;++i) a[i]=read();
for(int ii=1;ii<=m;++ii){
qq[ii].op=read();
if(qq[ii].op==3){
qq[ii].x=now;get_S();qq[ii].y=now-1;int k=qq[ii].k=read();ull tmp=0;
for(int i=1;i<=k;++i) tmp=tmp*k1+s[qq[ii].x+i-1];ins1(tmp);
for(int i=qq[ii].x+k;i<=qq[ii].y;++i){
tmp-=s[i-k]*bin[k-1];tmp=tmp*k1+s[i];ins1(tmp);
}continue;
}qq[ii].x=read();if(qq[ii].op==1) qq[ii].y=read();
}for(int i=1;i<=n;++i) b[i][1]=a[i],ins(b[i][1],1);
for(int ii=1;ii<=m;++ii){
int op=qq[ii].op;
if(op==3){
int k=qq[ii].k;ull tmp=0;
for(int i=1;i<=k;++i) tmp=tmp*k1+s[qq[ii].x+i-1];ll res=hs(tmp);
for(int i=qq[ii].x+k;i<=qq[ii].y;++i){
tmp-=s[i-k]*bin[k-1];tmp=tmp*k1+s[i];
res=res*hs(tmp)%mod;
}printf("%lld\n",res);continue;
}int x=qq[ii].x;
if(op==1){
int y=qq[ii].y;pre[y]=x;succ[x]=y;
for(int i=1;i<50;++i){
if(!x) break;
for(int j=i+1;j<=50;++j){
if(!b[y][j-i]) break;
b[x][j]=b[x][i]*bin[j-i]+b[y][j-i];ins(b[x][j],1);
}x=pre[x];
}
}else{
int y=succ[x];pre[y]=0;succ[x]=0;
for(int i=1;i<50;++i){
if(!x) break;
for(int j=i+1;j<=50;++j){
if(!b[y][j-i]) break;ins(b[x][j],-1);b[x][j]=0;
}x=pre[x];
}
}
}return 0;
}