zoukankan      html  css  js  c++  java
  • [BZOJ2780] Sevenk Love Oimaster

    Description

    给定 (n) 个主串和 (m) 个询问,每次询问给定一个字符串,问它在多少个大串中作为子串出现过。

    Solution

    (n) 个主串构建广义后缀自动机,求出每个结点的在多少个主串中出现过,记为 (f[i])

    对于每个询问串,扔到自动机上跑,假设跑到了 (p) 点,则答案为 (f[p])

    下面考虑如何求 (f[]),我们在每次 extend 时,对 (cur) 记录一个贡献,并暴力沿着后缀链接往上跳,跳到的所有结点都记一次贡献,同时记录这个节点是否被这个主串记过贡献,遇到一个记过贡献的结点就结束

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 2000005;
    struct SAM
    {
        int len[N], ch[N][26], fa[N], ind, last, f[N], vis[N], bel;
        SAM()
        {
            ind = last = 1;
        }
        void puttag(int p)
        {
            /*f[p]++;
            vis[p]=bel;
            while(p!=fa[p] && fa[p] && vis[fa[p]]<bel)
            {
                p=fa[p];
                vis[p]=bel;
                f[p]++;
            }*/
            while(p && vis[p]<bel)
            {
                f[p]++;
                vis[p]=bel;
                p=fa[p];
            }
        }
        inline int extend(int id)
        {
            if(ch[last][id] && len[last]+1==len[ch[last][id]])
            {
                return ch[last][id]; //!
            }
            int cur = (++ ind), p, tmp, flag = 0; //!
            len[cur] = len[last] + 1;
            for (p = last; p && !ch[p][id]; p = fa[p]) ch[p][id] = cur;
            if (!p) fa[cur] = 1;
            else
            {
                int q = ch[p][id];
                if (len[q] == len[p] + 1) fa[cur] = q;
                else
                {
                    if(p==last) flag=1; //!
                    tmp = (++ ind);
                    len[tmp] = len[p] + 1;
                    for(int i=0; i<26; i++) ch[tmp][i] = ch[q][i];
                    f[tmp] = f[q];
                    fa[tmp] = fa[q];
                    for (; p && ch[p][id] == q; p = fa[p]) ch[p][id] = tmp;
                    fa[cur] = fa[q] = tmp;
                }
            }
            last = cur;
            return flag ? tmp : cur;//!
        }
        void extend(string s)
        {
            for(int i=0; i<s.length(); i++)
            {
                last = extend(s[i]-'a');
            }
            last = 1;
        }
        void make(string s)
        {
            int p=1;
            for(int i=0;i<s.length();i++)
            {
                int c=s[i]-'a';
                p=ch[p][c];
                puttag(p);
            }
        }
        int run(string s)
        {
            int p=1;
            for(int i=0;i<s.length();i++)
            {
                if(ch[p][s[i]-'a'])
                {
                    p=ch[p][s[i]-'a'];
                }
                else
                {
                    return 0;
                }
            }
            return f[p];
        }
        void print()
        {
            for(int i=1;i<=ind;i++)
            {
                cout<<i<<": fa="<<fa[i]<<" ch="<<ch[i][0]<<","<<ch[i][1]<<","<<ch[i][2]<<" "<<f[i]<<endl;
            }
        }
    } sam;
    
    string s[N];
    
    signed main()
    {
        ios::sync_with_stdio(false);
        int n,q;
        string str;
        cin>>n>>q;
        for(int i=1; i<=n; i++)
        {
            sam.bel=i;
            cin>>str;
            s[i]=str;
            sam.extend(str);
            //sam.print();
        }
        for(int i=1;i<=n;i++)
        {
            sam.bel=i;
            sam.make(s[i]);
            //cout<<"sam processing "<<i<<endl;
            //sam.print();
        }
        //sam.print();
        for(int i=1;i<=q;i++)
        {
            cin>>str;
            cout<<sam.run(str)<<endl;
        }
    }
    
    
  • 相关阅读:
    权重平等分布局And TableRow布局误区
    播放视频的框架Vitamio的使用问题
    Android上常见度量单位【xdpi、hdpi、mdpi、ldpi】解读
    使用PullToRefresh实现下拉刷新和上拉加载
    如何安全退出已调用多个Activity的Application?
    Stirng,Stringbuffer,Stringbuild的区别浅淡
    python3 logging
    从集合中筛选数据
    python3 模块
    python3 字符串的 maketrans,translate 方法详解
  • 原文地址:https://www.cnblogs.com/mollnn/p/13597223.html
Copyright © 2011-2022 走看看