bzoj3881[COCI2015]Divljak

写过阿狸的打字机应该就可以写这道题了…对S中的n个串构建AC自动机和fail树,然后每新来一个T中的串,就把这个串扔进AC自动机里走一遍,会经过一些节点,每个节点在fail树上到根的路径上的节点对应的串都在这个串里出现,那么我们把这些节点到根节点的路径的并上的每个节点都+1,那么按节点的dfs序排序,每个节点处+1,相邻节点(不包括第一个和最后一个)处-1即可.倍增LCA并不会被卡.如果写树剖LCA会更快一点.

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
struct node{
    node* ch[26],*fail;
    int num;
    node(int x){num=x;fail=0;memset(ch,0,sizeof(ch));}
}*root;int tot=0;
const int maxn=3000005;
int pos[maxn];
void Add(char *c,int x){
    node* p=root;
    while(*c){
        int t=(*c)-'a';
        if(p->ch[t]==NULL)p->ch[t]=new node(++tot);
        p=p->ch[t];++c;
    }
    pos[x]=p->num;
}
char str[maxn];
struct edge{
    int to,next;
}lst[maxn];int len=1,first[maxn];
void addedge(int a,int b){
    lst[len].to=b;lst[len].next=first[a];first[a]=len++;
}
int point[maxn],dfn[maxn],sz[maxn],depth[maxn],p[maxn][22],T;
void dfs(int x){
    sz[x]=1;dfn[x]=++T;
    for(int j=0;p[x][j];++j)p[x][j+1]=p[p[x][j]][j];
    for(int pt=first[x];pt;pt=lst[pt].next){
        depth[lst[pt].to]=depth[x]+1;p[lst[pt].to][0]=x;
        dfs(lst[pt].to);
        sz[x]+=sz[lst[pt].to];
    }
}
int lca(int u,int v){
    if(depth[u]<depth[v])swap(u,v);
    for(int j=21;j>=0;--j){
        if(depth[p[u][j]]>=depth[v])u=p[u][j];
    }
    if(u==v)return u;
    for(int j=21;j>=0;--j){
        if(p[u][j]!=p[v][j])u=p[u][j],v=p[v][j];
    }
    return p[v][0];
}
void getfail(){
    queue<node*> q;q.push(root);
    while(!q.empty()){
        node* x=q.front();q.pop();
        for(int i=0;i<26;++i){
            if(x->ch[i]){
                if(x==root)x->ch[i]->fail=root;
                else x->ch[i]->fail=x->fail->ch[i];
                q.push(x->ch[i]);
                addedge(x->ch[i]->fail->num,x->ch[i]->num);
            }else if(x==root)x->ch[i]=root;
            else x->ch[i]=x->fail->ch[i];
        }
    }
}
int seq[maxn],cnt;
int c[maxn];
void bit_add(int x){
    for(;x<=tot;x+=x&(-x))c[x]++;
}
void bit_del(int x){
    for(;x<=tot;x+=x&(-x))c[x]--;
}
int bit_sum(int x){
    int ans=0;for(;x;x-=x&(-x))ans+=c[x];return ans;
}
int main(){
    int n;scanf("%d",&n);
    root= new node(++tot);
    for(int i=1;i<=n;++i){
        scanf("%s",str);
        Add(str,i);
    }
    getfail();
    depth[1]=1;dfs(1);
    for(int i=1;i<=tot;++i)point[dfn[i]]=i;
    int q;scanf("%d",&q);
    int typ,x;
    while(q--){
        scanf("%d",&typ);
        if(typ==1){
            scanf("%s",str);
            node* p=root;cnt=0;
            for(int i=0;str[i];++i){
                p=p->ch[str[i]-'a'];seq[cnt++]=dfn[p->num];
            }
            sort(seq,seq+cnt);
            bit_add(seq[0]);
            for(int i=1;i<cnt;++i){
                if(seq[i]!=seq[i-1]){
                    bit_add(seq[i]);bit_del(dfn[lca(point[seq[i]],point[seq[i-1]])]);
                }
            }
        }else{
            scanf("%d",&x);x=pos[x];
            printf("%d
",bit_sum(dfn[x]+sz[x]-1)-bit_sum(dfn[x]-1));
        }
    }
    return 0;
}
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
struct node{
    node* ch[26],*fail;
    int num;
    node(int x){num=x;fail=0;memset(ch,0,sizeof(ch));}
}*root;int tot=0;
const int maxn=2000005;
int pos[maxn];
void Add(char *c,int x){
    node* p=root;
    while(*c){
        int t=(*c)-'a';
        if(p->ch[t]==NULL)p->ch[t]=new node(++tot);
        p=p->ch[t];++c;
    }
    pos[x]=p->num;
}
char str[maxn];
struct edge{
    int to,next;
}lst[maxn];int len=1,first[maxn];
void addedge(int a,int b){
    lst[len].to=b;lst[len].next=first[a];first[a]=len++;
}
int point[maxn],dfn[maxn],sz[maxn],depth[maxn],hvy[maxn],prt[maxn],top[maxn],T;
void dfs1(int x){
    sz[x]=1;
    for(int pt=first[x];pt;pt=lst[pt].next){
        depth[lst[pt].to]=depth[x]+1;prt[lst[pt].to]=x;
        dfs1(lst[pt].to);
        sz[x]+=sz[lst[pt].to];
        if(sz[lst[pt].to]>sz[hvy[x]])hvy[x]=lst[pt].to;
    }
}
void dfs2(int x){
    dfn[x]=++T;point[T]=x;
    if(hvy[x]){
        top[hvy[x]]=top[x];
        dfs2(hvy[x]);
        for(int pt=first[x];pt;pt=lst[pt].next){
            if(lst[pt].to!=hvy[x]){
                top[lst[pt].to]=lst[pt].to;
                dfs2(lst[pt].to);
            }
        }
    }
}
int lca(int u,int v){
    int t1=top[u],t2=top[v];
    while(t1!=t2){
        if(depth[t1]<depth[t2]){
            swap(t1,t2);swap(u,v);
        }
        u=prt[t1];t1=top[u];
    }
    return depth[u]<depth[v]?u:v;
}
void getfail(){
    queue<node*> q;q.push(root);
    while(!q.empty()){
        node* x=q.front();q.pop();
        for(int i=0;i<26;++i){
            if(x->ch[i]){
                if(x==root)x->ch[i]->fail=root;
                else x->ch[i]->fail=x->fail->ch[i];
                q.push(x->ch[i]);
                addedge(x->ch[i]->fail->num,x->ch[i]->num);
            }else if(x==root)x->ch[i]=root;
            else x->ch[i]=x->fail->ch[i];
        }
    }
}
int seq[maxn],cnt;
int c[maxn];
void bit_add(int x){
    for(;x<=tot;x+=x&(-x))c[x]++;
}
void bit_del(int x){
    for(;x<=tot;x+=x&(-x))c[x]--;
}
int bit_sum(int x){
    int ans=0;for(;x;x-=x&(-x))ans+=c[x];return ans;
}
int main(){
    int n;scanf("%d",&n);
    root= new node(++tot);
    for(int i=1;i<=n;++i){
        scanf("%s",str);
        Add(str,i);
    }
    getfail();
    depth[1]=1;dfs1(1);top[1]=1;dfs2(1);
    for(int i=1;i<=tot;++i)point[dfn[i]]=i;
    int q;scanf("%d",&q);
    int typ,x;
    while(q--){
        scanf("%d",&typ);
        if(typ==1){
            scanf("%s",str);
            node* p=root;cnt=0;
            for(int i=0;str[i];++i){
                p=p->ch[str[i]-'a'];seq[cnt++]=dfn[p->num];
            }
            sort(seq,seq+cnt);
            bit_add(seq[0]);
            for(int i=1;i<cnt;++i){
                if(seq[i]!=seq[i-1]){
                    bit_add(seq[i]);bit_del(dfn[lca(point[seq[i]],point[seq[i-1]])]);
                }
            }
        }else{
            scanf("%d",&x);x=pos[x];
            printf("%d
",bit_sum(dfn[x]+sz[x]-1)-bit_sum(dfn[x]-1));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/liu-runda/p/6488677.html