首页 > 代码库 > BZOJ 3881 Coci2015 Divljak fail树+树链的并

BZOJ 3881 Coci2015 Divljak fail树+树链的并

题目大意:给定两个字符串集合S和T,初始给定S集合中的所有字符串,不断向T集合中添加字符串,以及询问S集合中的某个字符串在T集合中的多少个字符串中出现过

神题- -

首先对S集合的所有字符串构建fail树

T集合中每加入一个字符串,我们就将这个字符串在AC自动机上跑一遍,并记录经过的所有节点

根据fail树的性质,这些节点到根路径上的所有节点的并集的出现次数都加了1

因此我们要求的就是树链的并

求法如下:

将所有节点按照DFS序排序

每个点到根的路径上的所有节点权值+1

相邻两个点的LCA到根的路径上的所有节点权值-1

即是树链的并

当然我们不必修改路径查询单点 只需对单点进行修改 然后查询子树 用树状数组维护DFS序即可

这代码长度。。。。为了防止内存爆炸我用了线段树+RMQLCA。。。namespace套namespace泥萌怕不怕-。-

暴力艹标程是什么节奏0 0 快卡掉他们- -

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 2002002
using namespace std;
int n,m,limit;
char s[M];
namespace BIT{
    int c[M];
    void Update(int x,int y)
    {
        for(;x<=limit;x+=x&-x)
            c[x]+=y;
    }
    int Get_Ans(int x)
    {
        int re=0;
        for(;x;x-=x&-x)
            re+=c[x];
        return re;
    }
}
namespace Fail_Tree{
    struct abcd{
        int to,next;
    }table[M];
    int head[M],tot;
    int fa[M],dpt[M],pos[M],into[M],ed[M];
    namespace ZKW_Segtree{
        int Q,tree[8389000];
        bool Compare(int x,int y)
        {
            if(!x) return false;
            if(!y) return true;
            return dpt[x]<dpt[y];
        }
        void Build_Tree()
        {
            int i;
            for(i=Q-1;i;i--)
                tree[i]=min(tree[i<<1],tree[i<<1|1],Compare);
        }
        int Query(int x,int y)
        {
            int re=0;
            for(x+=Q-1,y+=Q+1;x^y^1;x>>=1,y>>=1)
            {
                if(~x&1) re=min(re,tree[x^1],Compare);
                if( y&1) re=min(re,tree[y^1],Compare);
            }
            return re;
        }
    }
    void DFS(int x,int array[])
    {
        static int cnt1,cnt2;
        int i;
        dpt[x]=dpt[fa[x]]+1;
        pos[x]=++cnt1;
        array[into[x]=++cnt2]=x;
        for(i=head[x];i;i=table[i].next)
        {
            fa[table[i].to]=x;
            DFS(table[i].to,array);
            array[++cnt2]=x;
        }
        ed[x]=cnt1;
    }
    void Add(int x,int y)
    {
        table[++tot].to=y;
        table[tot].next=head[x];
        head[x]=tot;
    }
    void Build_Tree()
    {
        using namespace ZKW_Segtree;
        for(Q=1;Q<=limit+limit;Q<<=1);
        DFS(1,tree+Q);
        ZKW_Segtree::Build_Tree();
    }
    int LCA(int x,int y)
    {
        x=into[x];y=into[y];
        if(x>y) swap(x,y);
        return ZKW_Segtree::Query(x,y);
    }
}
namespace Aho_Corasick_Automaton{
    struct Trie{
        Trie *son[26],*fail;
    }*root,mempool[M],*C=mempool;
    Trie *pos[100100];
    void Insert(Trie *&p,char *s,int id)
    {
        if(!p) p=++C;
        if(!*s)
        {
            pos[id]=p;
            return ;
        }
        Insert(p->son[*s-'a'],s+1,id);
    }
    void Build_Tree()
    {
        static Trie *q[M];
        int i,r=0,h=0;
        for(i=0;i<26;i++)
        {
            if(root->son[i])
                (q[++r]=root->son[i])->fail=root;
            else
                root->son[i]=root;
        }
        while(r!=h)
        {
            Trie *p=q[++h];
            for(i=0;i<26;i++)
            {
                if(p->son[i])
                    (q[++r]=p->son[i])->fail=p->fail->son[i];
                else
                    p->son[i]=p->fail->son[i];
            }
        }
        for(i=2;i<=C-mempool;i++)
            Fail_Tree::Add(mempool[i].fail-mempool,i);
        limit=C-mempool;
    }
    int Get_Points(char *s,int a[])
    {
        int i;
        Trie *p=root;
        for(i=1;s[i];i++)
        {
            p=p->son[s[i]-'a'];
            a[i]=p-mempool;
        }
        return a[i]=-1,i-1;
    }
}
bool Compare(int x,int y)
{
    using namespace Fail_Tree;
    return pos[x]<pos[y];
}
int main()
{
    int i,j,p,x;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        Aho_Corasick_Automaton::Insert(Aho_Corasick_Automaton::root,s+1,i);
    }
    Aho_Corasick_Automaton::Build_Tree();
    Fail_Tree::Build_Tree();
    static int a[M],top;
    cin>>m;
    using namespace Fail_Tree;
    for(i=1;i<=m;i++)
    {
        scanf("%d",&p);
        if(p==1)
        {
            scanf("%s",s+1);
            x=Aho_Corasick_Automaton::Get_Points(s,a);
            sort(a+1,a+x+1,Compare);
            for(top=0,j=1;j<=x;j++)
                if(a[j]!=a[j+1])
                    a[++top]=a[j];
            for(j=1;j<=top;j++)
            {
                x=a[j];
                BIT::Update(pos[x],1);
                if(j>1)
                    BIT::Update(pos[LCA(a[j-1],x)],-1);
            }
        }
        else
        {
            scanf("%d",&x);
            p=Aho_Corasick_Automaton::pos[x]-Aho_Corasick_Automaton::mempool;
            printf("%d\n",BIT::Get_Ans(ed[p])-BIT::Get_Ans(pos[p]-1) );
        }
    }
    return 0;
}


BZOJ 3881 Coci2015 Divljak fail树+树链的并