题目:https://loj.ac/problem/2303
想到合并的时候可以只考虑接口附近的50个,但不太会分析复杂度,而且没有清楚地想到用哈希值对应个数。
看了题解才会……
一直想用 splay ,其实链表就可以。用 unsigned long long 就不会被卡。
不能用 map ,而是要用哈希表把字符串的哈希值映射到个数上。
#include<cstdio> #include<cstring> #include<algorithm> #define ll unsigned long long using namespace std; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } const int mod=998244353; const ll bs=10009; const int N=2e5+5,m2=1e6+3,M=1e7+5,K=55; int n,m,vl[N],pr[N],nt[N],ct[M]; ll tp[M],p[K],bin[K];char s[M];//ll!!! not int namespace H{ int hd[m2+5],xnt,nxt[M];ll to[M]; int get(ll x) { int h=x%m2; for(int i=hd[h];i;i=nxt[i]) if(to[i]==x)return i; to[++xnt]=x;nxt[xnt]=hd[h];hd[h]=xnt; return xnt; } } void mrg(int x,int y,bool fx) { if(!fx){nt[x]=y; pr[y]=x;} else{y=nt[x]; nt[x]=pr[y]=0;} int tot=0,cr=y; while(cr) { tot++; tp[tot]=(tp[tot-1]*bs+vl[cr]); cr=nt[cr]; if(tot==49)break; } int tt=0; cr=x; while(cr) { tt++; p[tt]=(p[tt-1]+vl[cr]*bin[tt-1]); cr=pr[cr]; if(tt==49)break; } for(int i=tt;i;i--) for(int j=1;j<=tot;j++) { if(i+j>50)break; ll h=p[i]*bin[j]+tp[j]; int tp=H::get(h); if(fx)ct[tp]--; else ct[tp]++; } } int main() { n=rdn();m=rdn(); bin[0]=1; for(int i=1;i<=50;i++) { bin[i]=bin[i-1]*bs; } for(int i=1;i<=n;i++) { vl[i]=rdn(); int k=H::get(vl[i]); ct[k]++; } for(int i=1,op,x,y;i<=m;i++) { op=rdn(); if(op==1){ x=rdn();y=rdn();mrg(x,y,0);} if(op==2){ x=rdn();mrg(x,0,1);} if(op==3) { scanf("%s",s+1); x=rdn(); y=strlen(s+1); for(int j=1;j<=y;j++) tp[j]=(tp[j-1]*bs+(s[j]-'0')); int ans=1; for(int j=x;j<=y;j++) { ll h=tp[j]-tp[j-x]*bin[x]; int tp=H::get(h); ans=(long long)ans*ct[H::get(h)]%mod; } printf("%d ",ans); } } return 0; }