正常来说,单次操作的复杂度是 $O(k^2)$,然后整体复杂度是 $O(nk^2)$.
但是我们发现每次合并两个蚯蚓的复杂度的极限是 $O( min(size_{min},50) \times 50)$.
然后根据启发式合并的复杂度分析,即使要求遍历完 $size_{min}$,复杂度最高也就是 $O(n \log n k)$.
这个的极限也就是 $O(10^8)$ 左右,再加上跑不满那个 $O(\log n)$,实际运行速度比较快.
存储哈希值和合并蚯蚓用的都是链表.
可以开两个模数,一个小于 $10^7$,一个是 $998244353$,速度应该比 $map$ 之类的快一点.
code:
#include <set> #include <map> #include <cstdio> #include <cstring> #include <algorithm> #define N 200009 #define ll long long #define MA 9999071 #define MB 998244353 #define setIO(s) freopen(s".in","r",stdin) using namespace std; const int A=233; const int B=2333; int n,m,edges,cnt; int ST[N],ED[N],SIZE[N]; int BA[200000],BB[200000]; int hd[MA+233],nex[N*100]; int val[N*100],si[N*100]; char str[10000008]; int seqa[10000008]; int seqb[10000008]; struct data { int v,l,r; }a[N]; int find(int x,int y) { ++cnt; for(int i=hd[x];i;i=nex[i]) { if(val[i]==y) return 1; } return 0; } void upd(int x,int y,int d) { ++cnt; for(int i=hd[x];i;i=nex[i]) { ++cnt; if(val[i]==y) { si[i]+=d; return; } } } int query(int x,int y) { ++cnt; for(int i=hd[x];i;i=nex[i]) { if(val[i]==y) return si[i]; } return 0; } void ins(int x,int y) { ++cnt; if(find(x,y)) { upd(x,y,1); } else { nex[++edges]=hd[x]; hd[x]=edges,val[edges]=y,si[edges]=1; } } void del(int x,int y) { upd(x,y,-1); } void init() { BA[0]=BB[0]=1; for(int i=1;i<2000;++i) { BA[i]=(ll)BA[i-1]*A%MA; BB[i]=(ll)BB[i-1]*B%MB; } } void merge(int x,int y) { x=ST[x]; int ex=ED[x],ey=ED[y]; int len=1,ha=0,hb=0; for(int i=ex;len<=50&&i;i=a[i].l) { ha=(ll)(ha+(ll)a[i].v*BA[len]%MA)%MA; hb=(ll)(hb+(ll)a[i].v*BB[len]%MB)%MB; int hta=ha; int htb=hb; for(int j=y,p=len+1;j&&p<=50;j=a[j].r) { hta=(ll)((ll)hta*A%MA+(ll)a[j].v*A%MA)%MA; htb=(ll)((ll)htb*B%MB+(ll)a[j].v*B%MB)%MB; ins(hta,htb); ++p; } ++len; } a[ex].r=y; a[y].l=ex; ST[ED[y]]=x; ED[x]=ED[y]; } void split(int x) { int y=a[x].r; int ra=rand(),sx,ex=x,sy=y,ey; if(ra&1) { for(ey=y;a[ey].r;ey=a[ey].r); sx=ST[ey]; } else { for(sx=x;a[sx].l;sx=a[sx].l); ey=ED[sx]; } int len=1,ha=0,hb=0; for(int i=ex;len<=50&&i;i=a[i].l) { ha=(ll)(ha+(ll)a[i].v*BA[len]%MA)%MA; hb=(ll)(hb+(ll)a[i].v*BB[len]%MB)%MB; int hta=ha; int htb=hb; for(int j=y,p=len+1;j&&p<=50;j=a[j].r) { ++cnt; hta=(ll)((ll)hta*A%MA+(ll)a[j].v*A%MA)%MA; htb=(ll)((ll)htb*B%MB+(ll)a[j].v*B%MB)%MB; del(hta,htb); ++p; } ++len; } a[x].r=0; a[y].l=0; ED[sx]=x; ST[x]=sx,ED[x]=x; ST[ey]=y; ED[y]=ey,ST[y]=y; } int main() { // setIO("input"); scanf("%d%d",&n,&m); init(); for(int i=1;i<=n;++i) { scanf("%d",&a[i].v); ED[i]=ST[i]=i,SIZE[i]=1; a[i].l=a[i].r=0; ins((ll)a[i].v*A%MA,(ll)a[i].v*B%MB); } int x,y,z; for(int T=1;T<=m;++T) { int op; scanf("%d",&op); if(op==1) { scanf("%d%d",&x,&y); merge(x,y); } if(op==2) { scanf("%d",&x); split(x); } if(op==3) { int k,len; scanf("%s%d",str+1,&k); len=strlen(str+1); seqa[0]=seqb[0]=0; for(int i=1;i<=len;++i) { seqa[i]=(ll)((ll)seqa[i-1]*A%MA+(ll)(str[i]-'0')*A%MA)%MA; seqb[i]=(ll)((ll)seqb[i-1]*B%MB+(ll)(str[i]-'0')*B%MB)%MB; } int ans=1; for(int i=k;i<=len;++i) { int ca=(ll)(seqa[i]-(ll)seqa[i-k]*BA[k]%MA+MA)%MA; int cb=(ll)(seqb[i]-(ll)seqb[i-k]*BB[k]%MB+MB)%MB; ans=(ll)ans*query(ca,cb)%998244353; } printf("%d\n",ans); } } return 0; }