zoukankan      html  css  js  c++  java
  • 洛谷P5840 [COCI2015]Divljak (AC自动机+fail树上dfs序+树上差分线段树维护)

    题目链接:https://www.luogu.com.cn/problem/P5840

    解法:如题所示,不得不承认是一道非常好的题,就是有点麻烦qwq。首先考虑用S建AC自动机,然后对每一个点建fail[i]->i的dfs树,然后把每次添加的T串丢到AC自动机上跑。每次跑的时候记录T串每个位置在AC自动机里的位置。排序后(因为如果不排序的话,这些点就杂乱无章,就无法有效地进行树上差分,我们要的是每次T串丢进来看该点有没有使用过而已,所以如果你学过虚树会有所了解,用树上差分就是2个点+1,其LCA-1,为什么是-1而不是-2呢?因为我们需要记录该点有没有使用过,使用过的话就一直是1,最后维护的线段树其实就是查询的点包括其子树一共有几个点,因为根据fail指针的性质我们可以知道,一旦他儿子有匹配到,那他自己必有匹配。大概就是这样子吧,具体看代码,感觉啰里啰嗦自己还说不清。

    AC代码:

    #include<bits/stdc++.h>
    #pragma GCC optimize(2)
    #define ll long long
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,n,a) for(int i=n;i>=a;i--)
    #define endl '
    '
    #define eps 0.000000001
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    #define IO ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
    const int INF=0x3f3f3f3f;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    const int mod=1e9+7;
    const int maxn=2e6+5;
    int tot,head[maxn];
    struct E{
        int to,next;
    }edge[maxn<<1];
    void add(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    class ac_auto{
        public:
            const static int maxn=2e6+100;
            int tot,root;
            int tree[maxn][30]; 
            int pos[maxn];
            int fail[maxn];int ans[1005];
            int newnode(){
                for(int i=0;i<26;i++){
                    tree[tot][i]=0;
                }
                pos[tot]=0;
                return tot++;
            }
            void init(){
                mem(ans,0);tot=0;
                root=newnode();
            }                
            void insert_(string s,int t){
                int now = root;
                for(int i=0;i<s.length();i++){
                    int id=s[i]-'a';
                    if(!tree[now][id]){
                        tree[now][id]=newnode();
                    }
                    now=tree[now][id];
                }
                pos[t]=now;
            }
            
            void getFail(){
                queue <int>q;
                for(int i=0;i<26;i++){
                    if(tree[0][i]){
                        fail[tree[0][i]] = 0;
                        q.push(tree[0][i]);
                    }
                }
                while(!q.empty()){
                    int now = q.front();
                    q.pop();
                    for(int i=0;i<26;i++){
                        if(tree[now][i]){
                            fail[tree[now][i]] = tree[fail[now]][i];
                            q.push(tree[now][i]);
                        }
                        else
                            tree[now][i] = tree[fail[now]][i];
                    }
                }
            }    
    }acam;
    int fa[maxn],dep[maxn],siz[maxn],son[maxn];
    void dfs1(int u,int f){
        fa[u]=f;
        dep[u]=dep[f]+1;
        siz[u]=1;
        int maxsize=-1;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(v==f) continue;
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[v]>maxsize){
                maxsize=siz[v];
                son[u]=v;
            }
        }
    }
    int tim,dfn[maxn],top[maxn];
    void dfs2(int u,int t){
        dfn[u]=++tim;
        top[u]=t;
        if(!son[u]) return ;
        dfs2(son[u],t);
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(v==fa[u]||v==son[u]) continue;
            dfs2(v,v);
        }
    }
    int LCA(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]) std::swap(x,y);
        return x;
    }
    class segment_tree{
        public:
            struct node{
                int l,r;
                int sum;
            }tree[10000010];
            
            inline void build(int i,int l,int r){
                tree[i].l=l;tree[i].r=r;
                if(l==r){
                    tree[i].sum=0;
                    return ;
                }
                int mid=(l+r)>>1;
                build(i*2,l,mid);
                build(i*2+1,mid+1,r);
                tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
            }
            
            inline int search(int i,int l,int r){
                if(tree[i].l>=l && tree[i].r<=r)
                    return tree[i].sum;
                if(tree[i].r<l || tree[i].l>r)  return 0;
                int s=0;
                if(tree[i*2].r>=l)  s+=search(i*2,l,r);
                if(tree[i*2+1].l<=r)  s+=search(i*2+1,l,r);
                return s;
            }
            
            inline void update(int i,int dis,int k){
                if(tree[i].l==tree[i].r){
                    tree[i].sum+=k;
                    return ;
                }
                if(dis<=tree[i*2].r)  update(i*2,dis,k);
                else  update(i*2+1,dis,k);
                tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
                return ;
            }        
    }st;
    bool cmp(int a,int b){
        return dfn[a]<dfn[b];
    }
    int a[maxn];
    void solve1(string s){
        int now=acam.root,tp=0;
        for(int i=0;i<s.length();i++){
            now = acam.tree[now][s[i]-'a'];
            a[++tp]=now;
        }
        sort(a+1,a+tp+1,cmp);
        bool flag=false;
        rep(i,1,tp){
            st.update(1,dfn[a[i]],1);
            if(flag){
                st.update(1,dfn[LCA(a[i],a[i-1])],-1);
            }else{
                flag=true;
            }
        }
    }
    int solve2(int x){
        return st.search(1,1,dfn[acam.pos[x]]+siz[acam.pos[x]]-1)-st.search(1,1,dfn[acam.pos[x]]-1);
    }
    int main(){
        int n;scanf("%d",&n);mem(head,-1);
        acam.init();
        rep(i,1,n){
            string s;cin>>s;
            acam.insert_(s,i);
        }
        acam.getFail();
        rep(i,1,acam.tot-1){
            add(acam.fail[i],i);
        }
        dfs1(0,acam.tot);
        dfs2(0,0);
        st.build(1,1,tim);
        int q;scanf("%d",&q);
        while(q--){
            int op;scanf("%d",&op);
            if(op==1){
                string s;cin>>s;
                solve1(s);
            }else{
                int x;scanf("%d",&x);
                printf("%d
    ",solve2(x));
            }
        }
    }
    View Code
  • 相关阅读:
    ES6中关于数据类型的拓展:Symbol类型
    ES里关于数组的拓展
    ES里关于对象的拓展
    ES6里关于函数的拓展(三)
    ES6里关于函数的拓展(二)
    ES6里关于函数的拓展(一)
    ES6里关于正则表达式的拓展
    ES6里关于模板字面量的拓展
    Android之怎样实现滑动页面切换【Fragment】
    java quartz的使用,做时间轮询调用 CronTrigger
  • 原文地址:https://www.cnblogs.com/Anonytt/p/13442455.html
Copyright © 2011-2022 走看看