• BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)


    Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的。
    接下来会发生q个操作,操作有两种形式:
    “1 P”,Bob往自己的集合里添加了一个字符串P。
    “2 x”,Alice询问Bob,集合T中有多少个字符串包含串S_x。(我们称串A包含串B,当且仅当B是A的子串)
    Bob遇到了困难,需要你的帮助。
     
     

    Input

    第1行,一个数n;
    接下来n行,每行一个字符串表示S_i;
    下一行,一个数q;
    接下来q行,每行一个操作,格式见题目描述。

    Output

    对于每一个Alice的询问,帮Bob输出答案。

    Sample Input

    3
    a
    bc
    abc
    5
    1 abca
    2 1
    1 bca
    2 2
    2 3

    Sample Output

    1
    2
    1

    Hint

    【数据范围】

    1 <= n,q <= 100000;

    Alice和Bob拥有的字符串长度之和各自都不会超过 2000000;

    字符串都由小写英文字母组成。

    之前就看过此题,但是不会树链求并,就搁着了。现在回来看还是可以做的。

          Alice在字符串集合为S,Bob的字符串集合为T。先对Alice的集合建立AC自动机,得到Fail树。对于T每次新加的字符串Str,Str在自动机上跑。能跑到的所有 位置,在Fail树上对应的位置到根的所有点都要加1,重复的不重复加,就涉及到去重,即用树链求并。

         把跑到是所有位置对应的Fail树位置按DFS序排序,每一个位置+1,相邻的LCA位置处-1。那么求T中有几个串含有某Si时,即是求Si在Fail树上的子树值之和。这里倍增求LCA会超时。

    这个人的代码风格和我一模一样哎(但是他的AC自动机写丑了)!!!因为是权限题,自己写一遍怕错了没法知晓,就假设我写了,去找个差不多的题写写,233。

    #include<bits/stdc++.h>
    using namespace std;
       
    #define N 2002010
    int ch[N][26],fail[N],ins[N],cnt;
    char s[N];
       
    int head[N],next[N],end[N];
    inline void addedge(int a,int b){
        static int q=1;end[q]=b,next[q]=head[a],head[a]=q++;
    }
       
    int in[N],out[N],dep[N],tclock;
    void dfs(int x){
        in[x]=++tclock;
        for(int j=head[x];j;j=next[j])
            dep[end[j]]=dep[x]+1,dfs(end[j]);
        out[x]=tclock;
    }
      
    namespace Lca_system{
        int Seq[N<<1],a[8383608],M,ins[N],cnt;
        inline void build_dfs(int x){
            ins[x]=++cnt;
            Seq[cnt]=x;
            for(int j=head[x];j;j=next[j]){
                build_dfs(end[j]);
                Seq[++cnt]=x;
            }
        }
        inline int Min(int x,int y){
            if(x==-1||y==-1)return x==-1?y:x;
            return dep[x]<dep[y]?x:y;
        }
        inline void init(){
            build_dfs(0);
            for(M=1;M<cnt+2;M<<=1);
            memset(a,-1,sizeof a);
            for(int i=1;i<=cnt;++i)a[M+i]=Seq[i];
            for(int i=M-1;i>=1;--i)a[i]=Min(a[2*i],a[2*i+1]);
        }
        inline int ask(int tl,int tr){
            int re=-1;
            for(tl+=M-1,tr+=M+1;tl^tr^1;tl>>=1,tr>>=1){
                if(~tl&1)re=Min(re,a[tl^1]);
                if(tr&1)re=Min(re,a[tr^1]);
            }
            return re;
        }
        inline int lca(int x,int y){
            x=ins[x],y=ins[y];
            if(x>y)swap(x,y);
            return ask(x,y);
        }
    }
      
    int seq[N],num;
       
    int A[N];
    inline void modify(int x,int c){
        for(;x<=cnt+1;x+=x&-x)A[x]+=c;
    }
    inline int ask(int x){
        int re=0;for(;x;x-=x&-x)re+=A[x];return re;
    }
       
    inline bool cmp(const int&x,const int&y){return in[x]<in[y];}
       
    inline int git(){
        int c,re;
        while(!isdigit(c=getchar()));
        re=c-'0';
        while(isdigit(c=getchar()))re=(re<<1)+(re<<3)+c-'0';
        return re;
    }
    char buf[100010*6],*o=buf;
    inline void print(int x){
        static int s[100];int top=0;
        if(!x)*o++=48;else{for(;x;x/=10)s[++top]=x%10;for(int i=top;i>=1;--i)*o++=48+s[i];}
        *o++='
    ';
    }
    int main(){
        int n=git();
        register int i,j;
           
        int len,p;
        for(i=1;i<=n;++i){
            scanf("%s",s);
            len=strlen(s),p=0;
            for(j=0;j<len;++j){
                if(!ch[p][s[j]-'a'])ch[p][s[j]-'a']=++cnt;
                p=ch[p][s[j]-'a'];
            }
            ins[i]=p;
        }
           
        queue<int>q;
        for(i=0;i<26;++i) if(ch[0][i]) q.push(ch[0][i]);
        int u,v,r;
        while(!q.empty()){
            u=q.front(),q.pop();
            for(i=0;i<26;++i)if((v=ch[u][i])){
                q.push(v);
                for(r=fail[u];r&&!ch[r][i];r=fail[r]);
                fail[v]=ch[r][i];
            }
        }
           
        for(i=1;i<=cnt;++i) addedge(fail[i],i);
        dep[0]=1,dfs(0);
        Lca_system::init();
           
        int Q=git();
           
        int qte,x;
        while(Q--){
            qte=git();
            if(qte==1){
                scanf("%s",s);
                len=strlen(s),p=0,num=0;
                for(i=0;i<len;++i){
                    while(p&&!ch[p][s[i]-'a'])p=fail[p];
                    p=ch[p][s[i]-'a'];
                    if(p) seq[++num]=p;
                }
                sort(seq+1,seq+num+1,cmp);
                for(i=1;i<=num;++i)modify(in[seq[i]],1);
                for(i=1;i<num;++i)modify(in[Lca_system::lca(seq[i],seq[i+1])],-1);
            }
            else{
                x=git();
                print(ask(out[ins[x]])-ask(in[ins[x]]-1));
            }
        }
           
        fwrite(buf,1,o-buf,stdout);
        return 0;
    }
  • 相关阅读:
    Vs2013在Linux开发中的应用(19): 启动gdb
    Codeforces Round #277 (Div. 2)---C. Palindrome Transformation (贪心)
    DataGridView依据下拉列表显示数据
    android POI搜索,附近搜索,周边搜索定位介绍
    HDU OJ Max sum 题目1003
    Android时时监測手机的旋转角度 依据旋转角度确定在什么角度载入竖屏布局 在什么时候载入横屏布局
    Hadoop架构设计、执行原理具体解释
    关联引用
    Linux性能诊断工具
    HDU 5089 Assignment(rmq+二分 或 单调队列)
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9253569.html
Copyright © 2020-2023  润新知