2018.12.24-3881-[Coci2015]Divljak

算法标签:AC自动机

思路:

我们可以先把所有s串在AC 自动机上跑一遍,考虑如果一个串出现了,则我所能指向的所有fail节点都可以获得贡献,于是我们建出一棵fail树。

接下来考虑把T串加入,自己思考我们发现如果只是单纯把我到根节点的路径权值都+1,我们可能会重复计算答案,于是就要树链合并,即按照dfs序排序后,每一只修改我和上一个点的lca到我的路径,就不会重复。有点卡空间,我的做法是lca用线段树维护区间d最小值找出lca,时间(常数大)换空间了。

没有强制在线所以可以用AC自动机写,如果强制在线bzoj2555,就只能用数据结构套数据结构维护了,可怕。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=3e6+5,M=1e5+5;
char s[N];queue<int> q;
int minn[N<<2],ch[N][26],n,Q,tot=1,head[N],ne[N],to[N],num[N<<1],id[N],kk;
int que[N],nt,g[N],d[N],cnt,dfn[N],sz[N],a[N],fail[N],idx;
il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;}
il void insert(int x,int y){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;}
bool cmp(int t1,int t2){return dfn[t1]<dfn[t2];}
il void add(int x,int v){for(;x<=tot;x+=x&-x)g[x]+=v;}
il int query(int x){int ans=0;for(;x;x-=x&-x)ans+=g[x];return ans;}
il int Min(int x,int y){return d[x]<d[y]?x:y;}
il int ins(){
    int l=strlen(s+1);int x=1;
    for(int i=1;i<=l;i++){
        if(!ch[x][s[i]-'a'])ch[x][s[i]-'a']=++tot;
        x=ch[x][s[i]-'a'];
    }
    return x;
}
il void dfs(int x){
    dfn[x]=++idx;sz[x]=1;num[id[x]=++kk]=x;
    for(int i=head[x];i;i=ne[i]){
        d[to[i]]=d[x]+1;dfs(to[i]);
        sz[x]+=sz[to[i]];num[++kk]=x;
    }
}
il void build(int x,int l,int r){
    if(l==r){minn[x]=num[l];return;}
    int mid=(l+r)>>1;
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    minn[x]=Min(minn[x<<1],minn[x<<1|1]);
}
il int qm(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr)return minn[x];
    int mid=(l+r)>>1;
    if(qr<=mid)return qm(x<<1,l,mid,ql,qr);
    else if(mid<ql)return qm(x<<1|1,mid+1,r,ql,qr);
    else return Min(qm(x<<1,l,mid,ql,qr),qm(x<<1|1,mid+1,r,ql,qr));
}
il int Lca(int x,int y){
    int l=id[x],r=id[y];if(l>r)swap(l,r);
    return qm(1,1,kk,l,r);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++){scanf(" %s",s+1);a[i]=ins();}
    q.push(1);
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=0;i<26;i++){
            if(!ch[x][i])continue;
            int tmp=fail[x];
            while(tmp>1&&!ch[tmp][i])tmp=fail[tmp];
            if(ch[tmp][i])fail[ch[x][i]]=ch[tmp][i];
            else fail[ch[x][i]]=1;q.push(ch[x][i]);
        }
    }
    for(int i=2;i<=tot;i++)insert(fail[i],i);
    d[1]=1;dfs(1);build(1,1,kk);int Q=read();
    while(Q--){
        int op=read();
        if(op==1){
            scanf(" %s",s+1);int l=strlen(s+1);
            int x=1,nt=0;que[++nt]=x;
            for(int i=1;i<=l;i++){
                while(x!=1&&!ch[x][s[i]-'a'])x=fail[x];
                if(ch[s[i]-'a'])x=ch[x][s[i]-'a'];que[++nt]=x;
            }
            sort(que+1,que+1+nt,cmp);add(dfn[que[1]],1);
            for(int j=2;j<=nt;j++){
                add(dfn[que[j]],1);
                add(dfn[Lca(que[j],que[j-1])],-1);
            }
        }
        else{
            int x=a[read()];printf("%d\n",query(dfn[x]+sz[x]-1)-query(dfn[x]-1));
        }
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Jessie-/p/10171586.html