BZOJ4212 神牛的養成計劃
阿新 • • 發佈:2018-11-10
題目大意
給定$n$個字串$S$,$m$次詢問,每次詢問給定兩個字串$s_1,s_2$,求$n$個字串中有多少個串滿足$s_1$是其字首且$s_2$是其後綴。
$n\leq 2000,m\leq 10^5 \sum |S|,\sum (|s_1|+|s_2|) \leq 2\times 10^6$
題解
考慮正反建$Trie$樹,原題就變為了在兩棵子樹中均出現的點有多少個。
你當然可以用主席樹加二維數點解決,其實也可以將每一個串按照正向$Trie$樹$Dfs$序排序,然後再反向建可持久化$Trie$,每次詢問就先找到正向$dfs$序要求的區間,接著在可持久化$Trie$的兩個對應的跟中沿著$s_2$的反串得出答案。
複雜度為$O(n\log n+\sum |S|+\sum (|s_1|+|s_2|)+m\log n)$。
所以其實$n$甚至可以出成$10^5$級。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define M 2220000 #define N 2010 using namespace std; namespace IO{ const int BS=(1<<19); int Top=0; char OT[BS],*OS=OT,SS[20]; const char *fin=OT+BS-1; void flush(){fwrite(OT,1,OS-OT,stdout);} void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;} void write(int x){ if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-'); while(x) SS[++Top]=x%10,x/=10; while(Top) Putchar(SS[Top]+'0'),--Top; } int read(){ int nm=0,fh=1; char cw=getchar(); for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh; for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0'); return nm*fh; } }using namespace IO; char ch[M],*s[N],s1[M],s2[M]; int n,m,p[M][26],tg[N],len[N]; int sz[M],dfn[M],node[N],tot,Rt,rt[N]; int cnt,t[M][26],od[N],sum[M]; int ins(int &x,char *k,int rem){ if(!x) x=++tot; if(!rem) return x; ins(t[x][k[0]-'a'],k+1,rem-1); } void dfs(int x){ if(!x) return; dfn[x]=++cnt,sz[x]=1; for(int i=0;i<26;i++) dfs(t[x][i]),sz[x]+=sz[t[x][i]]; } bool cmp(int x,int y){return dfn[node[x]]<dfn[node[y]];} void ist(int &x,int pre,char *k,int rem){ sum[x=++cnt]=sum[pre]+1; memcpy(p[x],p[pre],sizeof(p[x])); if(!rem) return; ist(p[x][k[0]-'a'],p[pre][k[0]-'a'],k-1,rem-1); } int qry(int x,int pre,char *k,int rem){ if(sum[x]==sum[pre]) return 0; if(!rem) return sum[x]-sum[pre]; return qry(p[x][k[0]-'a'],p[pre][k[0]-'a'],k-1,rem-1); } void match(int &l,int &r,int x,char *k,int rem){ if(!rem){l=dfn[x],r=dfn[x]+sz[x]-1;return;} match(l,r,t[x][k[0]-'a'],k+1,rem-1); } int fd(int tim){ int ls=1,rs=n,res=n+1,md; while(ls<=rs){ md=((ls+rs)>>1); if(dfn[node[od[md]]]>tim) rs=md-1; else res=md,ls=md+1; } return res; } int main(){ n=read(),s[0]=ch; for(int i=1;i<=n;i++){ s[i]=s[i-1]+len[i-1],od[i]=i; scanf("%s",s[i]),len[i]=strlen(s[i]); node[i]=ins(Rt,s[i],len[i]); } dfs(Rt),cnt=0,sort(od+1,od+n+1,cmp); for(int i=1;i<=n;i++) ist(rt[i],rt[i-1],s[od[i]]+len[od[i]]-1,len[od[i]]); for(int T=read(),ans=0,len1,len2,L,R;T;T--,write(ans),Putchar('\n')){ scanf("%s%s",s1,s2),len1=strlen(s1),len2=strlen(s2); for(int i=0;i<len1;i++) s1[i]=(s1[i]-'a'+ans)%26+'a'; for(int i=0;i<len2;i++) s2[i]=(s2[i]-'a'+ans)%26+'a'; match(L,R,Rt,s1,len1); if(!R){ans=0;continue;} L=fd(L-1),R=fd(R),ans=qry(rt[R],rt[L],s2+len2-1,len2); }flush();return 0; }