ZOJ-3288 AC自动机


          用模式串构造Trie树..用Trie树构造AC自动机...用AC自动机构造Trie图...为了在一个Trie图中能同时处理overlap 和 not overlap的情况..每个节点就要有两个计数器..

          overlap的计数器point[h].w[0]很好处理...就是普通的Trie图遍历目标串..到达一个点h..其point[h].w[0]++并且其所有Fail到0的点的w[0]都++...

          而对于not overlap的情况..是同样Trie图遍历目标串..但在更新point[h].w[1]时为了避免重叠覆盖...对于每个点h,从根节点到当前点的长度用point[h].length记录..最近一次更新point[h].w[1]时扫到目标串的位置用point[h].last记录...只有当   i-point[h].last>=point[h].length   时才让point[h].w[1]++并且更新point[h].last为i...这样就保证了每次更新point[h].w[1]时不会出现重叠的部分.        

          Segmentation Fault  了很多次...就是因为节点数开少了...仔细看题才发现题目给的空间是126M...囧..


Program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#define oo 1000000000
using namespace std;
struct node
{
       int son[26],fail,w[2],last,length;
}point[600005];
char s[100005],str[10];
int t[100005],a[100005];
queue<int> myqueue;
int main()
{
       freopen("input.txt","r",stdin);
       freopen("output.txt","w",stdout);
       int T,i,j,n,len,h,num,k;
       T=0;
       while (~scanf("%s",s))
       {
          //   if (T) printf("\n"); 
             T++;
             scanf("%d",&n);
             num=1;
             memset(point[0].son,0,sizeof(point[0].son));
             point[0].last=-oo;
             point[0].length=0;
             point[0].w[0]=point[0].w[1]=0;
             for (j=1;j<=n;j++)
             {
                    scanf("%d%s",&t[j],&str);
                    len=strlen(str);
                    h=0;
                    for (i=0;i<len;i++)
                    {
                          if (!point[h].son[str[i]-'a'])
                          {
                                point[h].son[str[i]-'a']=++num;
                                memset(point[num].son,0,sizeof(point[num].son));
                                point[num].last=-oo;
                                point[num].length=point[h].length+1;
                                point[num].w[0]=point[num].w[1]=0;
                          }
                          h=point[h].son[str[i]-'a'];
                    }
                    a[j]=h;
             }
             while (!myqueue.empty()) myqueue.pop();
             point[0].fail=0;
             for (i=0;i<26;i++) 
             {
                    point[point[0].son[i]].fail=0;
                    if (point[0].son[i]) myqueue.push(point[0].son[i]);
             }
             while (!myqueue.empty())
             {
                    h=myqueue.front();
                    myqueue.pop();
                    for (i=0;i<26;i++)
                    {
                          k=point[h].fail;
                          while (k && !point[k].son[i]) k=point[k].fail;
                          point[point[h].son[i]].fail=point[k].son[i];
                          if (point[h].son[i])
                              myqueue.push(point[h].son[i]);
                          else 
                              point[h].son[i]=point[k].son[i];
                    }
             }
             len=strlen(s);
             h=0;
             for (i=0;i<len;i++)
             {
                    h=point[h].son[s[i]-'a'];   
                    k=h;
                    while (k)
                    {   
                          point[k].w[0]++;
                          if (i-point[k].last>=point[k].length)
                          {
                                 point[k].w[1]++;
                                 point[k].last=i;
                          }
                          k=point[k].fail;
                    }
             }
             printf("Case %d\n",T);
             for (i=1;i<=n;i++) printf("%d\n",point[a[i]].w[t[i]]);
             printf("\n");
       }
       return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值