[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 }
View Code

 

posted @ 2016-10-10 19:01  czllgzmzl  阅读(292)  评论(0编辑  收藏  举报