【題解】P5212 SubString
阿新 • • 發佈:2021-12-15
發現只投了洛谷 blog,同步過來了
反正投不了了,隨便寫寫(其實這是卡常記錄)
演算法
查給定字串的出現次數常用 SAM,就是查 SAM 對應節點的 parent 樹子樹裡有多少個主鏈上的節點,向後加字串可以直接記錄節點時間戳等實現。
但是這題有強制線上,所以要支援的操作就是在 parent 樹上加點和更換父節點,查詢子樹和,顯然可用 LCT,但也可以用平衡樹維護 dfs 序實現,更換父節點即區間平移。
我寫了個 fhqTreap,發現用它做這個常數比 LCT 還大,開 O2 都只有45pts。
考慮優化常數,對於新建節點原本是先直接並在 dfs 序的最後,找到父節點時再插到對應區間。於是新建節點時暫不加進平衡樹,找到父節點了才直接加到父節點後面,於是就不開 O2 最劣解卡過了。
code
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> #include<set> #include<map> #include<stdlib.h> #include<time.h> using namespace std; #define re register typedef long long ll; inline int max(int x,int y){return x>y?x:y;} inline int min(int x,int y){return x<y?x:y;} inline void cmax(int &x,int y){if(x<y) x=y;} inline void cmin(int &x,int y){if(x>y) x=y;} inline void swp(int &x,int &y){x^=y^=x^=y;} const int N=1200050; int tot,la,ch[N][2],ml[N],fa[N],rt,ls[N<<1],rs[N<<1],pr[N<<1],sz[N<<1],sm[N<<1],v[N<<1],ff[N<<1]; char ss[N]; inline void mt(int &x){sz[x]=sz[ls[x]]+sz[rs[x]]+1,sm[x]=sm[ls[x]]+sm[rs[x]]+v[x],ff[ls[x]]=ff[rs[x]]=x,ff[x]=0;} inline int merge(int x,int y){ if(!x||!y) return x|y; if(pr[x]<pr[y]) return rs[x]=merge(rs[x],y),mt(x),x; return ls[y]=merge(x,ls[y]),mt(y),y; } inline void split(int x,int k,int &a,int &b){ if(!x) return a=b=0,void(); if(sz[ls[x]]>=k) b=x,split(ls[x],k,a,ls[x]); else a=x,split(rs[x],k-sz[ls[x]]-1,rs[x],b); mt(x); } inline int rk(int x){ int s=sz[ls[x]]+1; for(;x;x=ff[x]) if(x==rs[ff[x]]) s+=sz[ls[ff[x]]]+1; return s; } inline int xl(int &x){return (x<<1)-1;} inline int xr(int &x){return x<<1;} inline void newf(int x,int y,int ssm){ fa[x]=y,sz[xl(x)]=sz[xr(x)]=1,sm[xl(x)]=v[xl(x)]=ssm, pr[xl(x)]=rand(),pr[xr(x)]=rand(); int a=merge(xl(x),xr(x)),b;split(rt,rk(xl(y)),rt,b); rt=merge(merge(rt,a),b); } inline void chf(int x,int y){ fa[x]=y;int a,b; split(rt,rk(xr(x)),rt,b),split(rt,rk(xl(x))-1,rt,a), rt=merge(rt,b),split(rt,rk(xl(y)),rt,b),rt=merge(merge(rt,a),b); } inline void qry(int x,int &mask){ if(x){ int a,b; split(rt,rk(xr(x)),rt,b),split(rt,rk(xl(x))-1,rt,a), printf("%d\n",sm[a]),mask^=sm[a],rt=merge(merge(rt,a),b); } else putchar('0'),putchar('\n'); } inline void build(int c){ int p=la,x=++tot,q;ml[x]=ml[la]+1,la=x; while(!ch[p][c]&&p) ch[p][c]=x,p=fa[p]; if(!p) return newf(x,1,1),void(); if(ml[q=ch[p][c]]==ml[p]+1) return newf(x,q,1),void(); newf(++tot,fa[q],0),newf(x,tot,1),chf(q,tot),ml[tot]=ml[p]+1, ch[tot][0]=ch[q][0],ch[tot][1]=ch[q][1]; while(ch[p][c]==q&&p) ch[p][c]=tot,p=fa[p]; } inline int walk(char *s,int n){int x=1;for(re int i=0;i<n;++i) x=ch[x][s[i]-'A'];return x;} inline int inputs(char *s,int mask){ scanf("%s",s);int n=strlen(s); for(re int j=0;j<n;++j) mask=(mask*131+j)%n,swap(s[mask],s[j]); return n; } signed main(){ srand(time(0)); int T,mask=0,n;char kd[7]; scanf("%d%s",&T,ss); la=tot=1,sz[1]=sz[2]=0,pr[1]=rand(),pr[2]=rand(),rt=merge(1,2); for(re int i=0,l=strlen(ss);i<l;++i) build(ss[i]-'A'); while(T--){ scanf("%s",kd); if(kd[0]=='A') for(re int i=0,l=inputs(ss,mask);i<l;++i) build(ss[i]-'A'); else n=inputs(ss,mask),qry(walk(ss,n),mask); } return 0; }