BZOJ3881 Coci2015Divljak(AC自动机+树上差分+树状数组)

  建出AC自动机及其fail树,每次给新加入的串在AC自动机上经过的点染色,问题即转化为子树颜色数。显然可以用dfs序转成序列问题树状数组套权值线段树解决,显然过不掉。事实上直接树上差分,按dfs序排序后lca处-1,树状数组维护子树和即可。

  又一次写了cmp后没放进sort,心态爆炸。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 2000010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,m,trie[N][26],fail[N],val[N],id[N],q[N],tree[N],end[N],tmp[N],cnt;
char s[N];
void add(int k,int x){while (k<=cnt) tree[k]+=x,k+=k&-k;}
int query(int k){int s=0;while (k) s+=tree[k],k-=k&-k;return s;}
namespace Tree
{
    int p[N],t,dfn[N],size[N],fa[N][22],deep[N],cnt;
    struct data{int to,nxt;}edge[N];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void dfs(int k)
    {
        dfn[k]=++cnt;size[k]=1;
        for (int i=p[k];i;i=edge[i].nxt)
        {
            deep[edge[i].to]=deep[k]+1;
            fa[edge[i].to][0]=k;
            dfs(edge[i].to);
            size[k]+=size[edge[i].to];
        }
    }
    void build()
    {
        cnt=0;dfs(0);
        for (int j=1;j<22;j++)
            for (int i=0;i<cnt;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    }
    int lca(int x,int y)
    {
        if (deep[x]<deep[y]) swap(x,y);
        for (int j=21;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];
        if (x==y) return x;
        for (int j=21;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
        return fa[x][0];
    }
}
void ins(char *s,int n,int p)
{
    int k=0;
    for (int i=1;i<=n;i++)
    {
        if (!trie[k][s[i]-'a']) trie[k][s[i]-'a']=++cnt;
        k=trie[k][s[i]-'a'];
    }
    end[p]=k;
}
void build()
{
    int head=0,tail=0;for (int i=0;i<26;i++) if (trie[0][i]) q[++tail]=trie[0][i],Tree::addedge(0,trie[0][i]);
    do
    {
        int x=q[++head];
        for (int i=0;i<26;i++)
        if (trie[x][i]) fail[trie[x][i]]=trie[fail[x]][i],Tree::addedge(fail[trie[x][i]],trie[x][i]),q[++tail]=trie[x][i];
        else trie[x][i]=trie[fail[x]][i];
    }while (head<tail);
    Tree::build();
}
bool cmp(const int&a,const int&b)
{
    return Tree::dfn[a]<Tree::dfn[b];
}
void run(char *a,int n)
{
    int k=0,cnt=0;tmp[++cnt]=0;
    for (int i=1;i<=n;i++) tmp[++cnt]=k=trie[k][a[i]-'a'];
    sort(tmp+1,tmp+cnt+1,cmp);
    for (int i=1;i<=cnt;i++) add(Tree::dfn[tmp[i]],1);
    for (int i=2;i<=cnt;i++) add(Tree::dfn[Tree::lca(tmp[i-1],tmp[i])],-1);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj3881.in","r",stdin);
    freopen("bzoj3881.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    m=read();
    for (int i=1;i<=m;i++)
    {
        scanf("%s",s+1);n=strlen(s+1);
        ins(s,n,i);
    }
    build();cnt++;
    m=read();
    while (m--)
    {
        int op=read();
        if (op==1)
        {
            scanf("%s",s+1);n=strlen(s+1);
            run(s,n);
        }
        else
        {
            int x=read();
            printf("%d\n",query(Tree::dfn[end[x]]+Tree::size[end[x]]-1)-query(Tree::dfn[end[x]]-1));
        }
    }
    return 0;
}

 

posted @ 2019-01-02 19:50  Gloid  阅读(170)  评论(0编辑  收藏  举报