zoukankan      html  css  js  c++  java
  • BZOJ_3881_[Coci2015]Divljak_AC自动机+dfs序+树状数组

    BZOJ_3881_[Coci2015]Divljak_AC自动机+dfs序+树状数组

    Description

    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;

    对S集中的串建立AC自动机。
    首先我们要知道fail树子树中有多少个结点就代表它是多少个串的后缀。
    当我们插入一个串时,沿着AC自动机走,将所有点+1,然后子树和就代表有多少包含这个串。
    但题中要求的是集合T中有多少字符串满足条件,因此我们需要去重。
    即求一些根到点路径的并。
    把点按dfs序排序,然后加入每个点的贡献,减去lca的贡献。
     
    代码:
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    inline char nc() {
        static char buf[100000],*p1,*p2;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    int rd() {
        int x=0;char c=nc();
        while(c<'0'||c>'9') c=nc();
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=nc();
        return x;
    }
    #define N 2000050
    #define M 100050
    int fail[N],ch[N][26],xx[M],yy[M],n,idx,cnt=1,pos[M],Q[N],l,r,head[N],to[N],nxt[N],c[N],dfn[N],son[N],a[N],m;
    int f[22][N],dep[N];
    bool cmp(int x,int y) {
        return dfn[x]<dfn[y];
    }
    inline void add(int u,int v) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    }
    void fix(int x,int v) {
        for(;x<=dfn[0];x+=x&(-x)) c[x]+=v;
    }
    int inq(int x) {
        int re=0; 
        for(;x;x-=x&(-x)) re+=c[x];
        return re;
    }
    void build_ac() {
        int i,p;
        for(i=0;i<26;i++) ch[0][i]=1;
        Q[r++]=1;
        while(l<r) {
            p=Q[l++];
            for(i=0;i<26;i++) {
                if(ch[p][i]) fail[ch[p][i]]=ch[fail[p]][i],Q[r++]=ch[p][i];
                else ch[p][i]=ch[fail[p]][i];
            }
        }
    }
    void dfs(int x) {
        int i; 
        dfn[x]=++dfn[0];
        for(i=head[x];i;i=nxt[i]) {
            f[0][to[i]]=x; dep[to[i]]=dep[x]+1;
            dfs(to[i]);
        }
        son[x]=dfn[0];
    }
    int lca(int x,int y) {
        int i;
        if(dep[x]<dep[y]) swap(x,y);
        for(i=21;i>=0;i--) {
            if(dep[f[i][x]]>=dep[y]) x=f[i][x];
        }
        if(x==y) return x;
        for(i=21;i>=0;i--) {
            if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
        }
        return f[0][x];
    }
    int main() {
        n=rd();
        int i,j,x;
        for(i=1;i<=n;i++) {
            char s=nc(); int p=1;
            while(s<'a'||s>'z') s=nc();
            for(;s>='a'&&s<='z';s=nc()) {
                int &k=ch[p][s-'a'];
                if(!k) k=++cnt;
                p=k;
            }
            pos[i]=p;
        }
        int tot=cnt; cnt=0;
        build_ac();
        for(i=1;i<=tot;i++) if(fail[i]) add(fail[i],i);
        dfs(1);
        for(i=1;(1<<i)<=tot;i++) {
            for(j=1;j<=tot;j++) {
                f[i][j]=f[i-1][f[i-1][j]];
            }
        }
        m=rd();
        int opt;
        while(m--) {
            opt=rd();
            if(opt==1) {
                a[0]=0;
                char s=nc(); int p=1;
                while(s<'a'||s>'z') s=nc();
                for(;s>='a'&&s<='z';s=nc()) {
                    p=ch[p][s-'a'];
                    a[++a[0]]=p; fix(dfn[p],1);
                }
                sort(a+1,a+a[0]+1,cmp);
                for(i=1;i<a[0];i++) {
                    fix(dfn[lca(a[i],a[i+1])],-1);
                }
            }else {
                x=rd();
                int p=pos[x];
                printf("%d
    ",inq(son[p])-inq(dfn[p]-1));
            }
        }
    }
    
  • 相关阅读:
    monads-are-elephants(转)
    程序语言简史(转)
    语法的省略不能造成编译器的歧义
    scala getter and setter
    隐式类型转换
    java 调用 scala
    列表的操作
    Scala HandBook
    Scala 高级编程练习
    Net 2.0 C# 专用的只读类Tuple
  • 原文地址:https://www.cnblogs.com/suika/p/9186887.html
Copyright © 2011-2022 走看看