码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 4641 K-string SAM理解

时间:2016-07-16 06:52:08      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4641

题意:有一个长度不超过5e4的字符串,Q(Q<=2e5)次操作;

操作分为:1 ch 想字符串末尾插入一个字符ch; 2 表示查询目前的字符串中子串出现次数不小于k次的不同子串数目;

思路:SAM在线求解;

对于每次找到将一个字符x插入到SAM之后,我们知道pre[p]所含有的Tx的后缀字符串数目为step[pre[np]]个,那么只需要每次插入之后更新下这些字符串出现的次数cnt即可;

由于Right(fa)与Right(r)没有交集(max(fa) = min(r) - 1),所以需要一直递推到root,但是root不能计算,因为root并没有表示后缀,只是一个init状态;

还有一点就是在拷贝q的信息到nq中时,主要把cnt的信息也拷贝过去;

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

#define maxn 100007
#define SIGMA_SIZE 26

struct SAM{
    int sz,tot,last,k;
    int g[maxn<<1][SIGMA_SIZE],pre[maxn<<1],step[maxn<<1];
    int vs[maxn<<1],cnt[maxn<<1];

    void newNode(int s){
        step[++sz] = s;
        pre[sz] = 0;
        vs[sz] = cnt[sz] = 0;
        memset(g[sz],0,sizeof(g[sz]));
    }

    void init(){
        tot = 0;
        sz = 0; last = 1;
        newNode(0);
    }

    int idx(char ch){return ch - a;}

    void Insert(char ch){
        newNode(step[last]+1);
        int v = idx(ch), p = last, np = sz;

        while(p && !g[p][v])
            g[p][v] = np,p = pre[p];    //知道找到Right集合中包含x的边的祖宗节点

        if(p){
            int q = g[p][v];
            if(step[q] == step[p] + 1)
                pre[np] = q;
            else{
                newNode(step[p]+1);
                int nq = sz;             //nq替换掉q节点
                for(int i = 0;i < SIGMA_SIZE;i++)
                    g[nq][i] = g[q][i];

                cnt[nq] = cnt[q];     //**
                pre[nq] = pre[q];
                pre[np] = pre[q] = nq;

                while(p && g[p][v] == q)
                    g[p][v] = nq,p = pre[p];
            }
        }
        else pre[np] = 1;
        for(int aux = np;aux != 1 && !vs[aux];aux = pre[aux]){
            if(++cnt[aux] >= k){
                tot += step[aux] - step[pre[aux]];
                vs[aux] = true;    //该父节点的子串已经加到tot中
            }
        }
        last = np;
    }
}SA;
char str[maxn];
int main()
{
    int n,Q;
    while(scanf("%d%d%d",&n,&Q,&SA.k) == 3){
        scanf("%s",str);
        SA.init();
        int len = strlen(str);
        for(int i = 0;i < len;i++){
            SA.Insert(str[i]);
        }
        int op;
        char ch[2];
        while(Q--){
            scanf("%d",&op);
            if(op & 1){
                scanf("%s",ch);
                SA.Insert(ch[0]);
            }
            else printf("%d\n",SA.tot);
        }
    }
}

 

hdu 4641 K-string SAM理解

标签:

原文地址:http://www.cnblogs.com/hxer/p/5675149.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!