[51nod1440]迈克打电话
有n只熊,从1到n进行编号。
第i只熊的电话号码是si。每只熊会给那些电话号码是他的子串的熊打电话(可能会给自己打)。
call(i, j) 表示第i只熊给第j只熊打电话的次数,也就是第j个串在第i个串中出现的次数。
迈克会有q次询问。每个询问中给出L,R,k,然后请您计算一下 sum{call(i,k)},L<=i<=R
Input
第一行包含两个整数n 和 q (1 ≤ n ≤ 2 × 10^5 , 1 ≤ q ≤ 5 × 10^5).
接下来n行,每行一个电话号码,第i行给出第i只熊的电话号码。每个号码只包含英文小写字符,并且非空,所有串的长度之和≤ 2 × 10^5
接下来q行,每行包含l,r,k(1 ≤ l ≤ r ≤ n 并且 1 ≤ k ≤ n)。
Output
对于每一个查询,输出答案并换行。
根据fail链建树,每次的查询变成统计 第l..r个字符串的所有前缀的结束节点 有多少个是在 查询串的结束节点的子树里。
按dfs序随便搞...直接主席树或者离线后树状数组都可以。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<cmath> 7 #define ll long long 8 #define ui unsigned int 9 #define ull unsigned long long 10 const int maxn=200233,mxnode=maxn*25; 11 struct zs{int too,pre;}e[maxn];int tott,last[maxn]; 12 int lc[mxnode],rc[mxnode],sm[mxnode],tt,rt[maxn]; 13 int ch[maxn][26],tot,pos[maxn],cnt,l[maxn],r[maxn],dl[maxn],fail[maxn]; 14 int l1[maxn],r1[maxn],tim; 15 int i,j,k,n,m; 16 int L,R,P,SM; 17 char s[maxn]; 18 19 int ra;char rx; 20 inline int read(){ 21 rx=getchar(),ra=0; 22 while(rx<'0'||rx>'9')rx=getchar(); 23 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 24 } 25 26 27 inline void insert(int a,int b){e[++tott].too=b,e[tott].pre=last[a],last[a]=tott;} 28 inline void trie(int n){ 29 int p=0,i,c; 30 for(i=1;i<=n;i++){ 31 c=s[i]-'a'; 32 if(!ch[p][c])ch[p][c]=++tot,p=tot;else p=ch[p][c]; 33 pos[++cnt]=p; 34 } 35 } 36 inline void getfail(){ 37 int l=0,r=1,i,now,j,p;dl[1]=0; 38 while(l<r){ 39 now=dl[++l]; 40 for(i=0;i<26;i++)if(ch[now][i]){ 41 dl[++r]=j=ch[now][i]; 42 for(p=fail[now];p&&!ch[p][i];p=fail[p]); 43 fail[j]=!now?0:ch[p][i],insert(fail[j],j);//printf(" %d - - ->%d\n",j,fail[j]); 44 } 45 } 46 } 47 48 void dfs(int x){ 49 l1[x]=++tim; 50 for(int i=last[x];i;i=e[i].pre)dfs(e[i].too); 51 r1[x]=tim; 52 } 53 54 void insert(int &x,int pre,int a,int b){ 55 sm[(x=++tt)]=sm[pre]+1; 56 if(a==b)return; 57 int mid=a+b>>1; 58 if(P<=mid)rc[x]=rc[pre],insert(lc[x],lc[pre],a,mid); 59 else lc[x]=lc[pre],insert(rc[x],rc[pre],mid+1,b); 60 } 61 void query(int x,int pre,int a,int b){ 62 if((L<=a&&R>=b)||!x){SM+=sm[x]-sm[pre];return;} 63 int mid=a+b>>1; 64 if(L<=mid)query(lc[x],lc[pre],a,mid); 65 if(R>mid)query(rc[x],rc[pre],mid+1,b); 66 } 67 68 char ss[10];int len; 69 inline void outx(int x){ 70 if(!x){putchar('0');return;} 71 while(x)ss[len++]=x%10,x/=10; 72 while(len)putchar(ss[--len]+48); 73 } 74 int main(){ 75 n=read(),m=read(); 76 for(i=1;i<=n;i++) 77 scanf("%s",s+1),l[i]=cnt+1, 78 trie(strlen(s+1)),r[i]=cnt; 79 getfail(); 80 dfs(0);tot++; 81 for(i=1;i<=cnt;i++)//printf("i:%d dfn:%d\n",i,l1[pos[i]]), 82 P=l1[pos[i]],insert(rt[i],rt[i-1],1,tot); 83 84 int x,y,kk; 85 while(m--) 86 x=read(),y=read(),kk=read(), 87 L=l1[pos[r[kk]]],R=r1[pos[r[kk]]],SM=0,query(rt[r[y]],rt[l[x]-1],1,tot), 88 // printf(" %d-----%d\n",L,R), 89 printf("%d\n",SM); 90 }