zoukankan      html  css  js  c++  java
  • CodeForces

    题意:给定字符串S,然后M个字符串T。Q次询问,每次给出(L,R,l,r),问S[l,r]在L到R这些T字符串中,在哪个串出现最多,以及次数。

    思路:把所有串建立SAM,然后可以通过倍增走到[l,r]在SAM上的位置p,然后在这个位置p上求,求的过程就是一个线段树求区间最值。 现在的关键是得到线段树,这个线段树记录了endpos,这个可以用启发式合并。  

    注意现在是广义后缀自动机,不能用拓扑排序合并线段树。 必须用fail树DFS来合并。 不然会出错。 具体我也不知道,不过我估计是因为广义自动机里面有空串导致的。 因为空串导致x和fax的长度相同,这样拓扑就会出错。 而普通的SAM没有这种情况。

        #include<bits/stdc++.h>
        #define rep2(i,a,b) for(int i=a;i>=b;i--)
        #define rep(i,a,b) for(int i=a;i<=b;i++)
        using namespace std;
        const int maxn=1100010;
        char c[maxn],t[maxn];
        int rt[maxn],pos[maxn],fcy[maxn],N,M,Q,tot;
        int f[maxn][20],ans,num;
        struct in{
            int L,R,Mx,id;
        }s[maxn*20];
        void update(int now)
        {
            if(s[s[now].L].Mx>=s[s[now].R].Mx) {
                s[now].Mx=s[s[now].L].Mx;
                s[now].id=s[s[now].L].id;
            }
            else {
                s[now].Mx=s[s[now].R].Mx;
                s[now].id=s[s[now].R].id;
            }
        }
        void ins(int &now,int L,int R,int p)
        {
            if(!now) now=++tot;
            if(L==R){  s[now].Mx++; s[now].id=L; return ;}
            int Mid=(L+R)>>1;
            if(p<=Mid) ins(s[now].L,L,Mid,p);
            else ins(s[now].R,Mid+1,R,p);
            update(now);
        }
        void merge(int &now,int x,int y,int L,int R)
        {
            if(!x||!y) { now= x|y; return ;}
            now=++tot;int Mid=(L+R)>>1;
            if(L==R) { s[now].Mx=s[x].Mx+s[y].Mx; s[now].id=L; return ;}
            merge(s[now].L,s[x].L,s[y].L,L,Mid);
            merge(s[now].R,s[x].R,s[y].R,Mid+1,R);
            update(now);
        }
        void query(int Now,int L,int R,int l,int r)
        {
            if(!Now||l>r) return ;
            if(s[Now].Mx<num) return ;
            if(l<=L&&r>=R) {
                if(s[Now].Mx>num) num=s[Now].Mx,ans=s[Now].id;
                else if(s[Now].Mx==num&&num!=0) ans=min(ans,s[Now].id);
                return ;
            }
            int Mid=(L+R)>>1;
            if(l<=Mid) query(s[Now].L,L,Mid,l,r);
            if(r>Mid) query(s[Now].R,Mid+1,R,l,r);
        }
        struct SAM{
            int ch[maxn][26],fa[maxn],maxlen[maxn],cnt,last;
            int a[maxn],b[maxn];
            void init()
            {
                cnt=last=1;
                memset(ch[1],0,sizeof(ch[1]));
            }
            void add(int x,int id)
            {
                int np=++cnt,p=last; last=np;
                if(id>0) ins(rt[np],1,M,id);
                maxlen[np]=maxlen[p]+1; memset(ch[np],0,sizeof(ch[np]));
                while(p&&!ch[p][x]) ch[p][x]=np,p=fa[p];
                if(!p) fa[np]=1;
                else {
                    int q=ch[p][x];
                    if(maxlen[q]==maxlen[p]+1) fa[np]=q;
                    else {
                       int nq=++cnt; maxlen[nq]=maxlen[p]+1;
                       fa[nq]=fa[q]; fa[q]=fa[np]=nq;
                       memcpy(ch[nq],ch[q],sizeof(ch[q]));
                        while(p&&ch[p][x]==q) ch[p][x]=nq,p=fa[p];
                    }
                }
            }
            vector<int>G[maxn];
            void dfs(int u)
            {
                for(int i=0;i<G[u].size();i++){
                    int v=G[u][i];
                    f[v][0]=u; dfs(v);
                    merge(rt[u],rt[u],rt[v],1,M);
                }
            }
            void DFS()
            {
                rep(i,2,cnt) G[fa[i]].push_back(i);
                dfs(1);
            }
        }T;
        void solve()
        {
            int L,R,l,r,len;
            scanf("%d%d%d%d",&L,&R,&l,&r);
            len=r-l+1;
            int now=pos[r];
            if(T.maxlen[now]<len) {
                printf("%d %d
    ",L,0);
                return ;
            }
            for(int i=19;i>=0;i--)
                if(T.maxlen[f[now][i]]>=len) now=f[now][i];
            ans=L; num=0;
            query(rt[now],1,M,L,R);
            printf("%d %d
    ",ans,num);
        }
        int main()
        {
            T.init();
            scanf("%s",t+1);
            N=strlen(t+1); T.last=1;
            rep(i,1,N) T.add(t[i]-'a',0),pos[i]=T.last;
            scanf("%d",&M);
            rep(i,1,M) {
                T.last=1;
                scanf("%s",c+1); N=strlen(c+1);
                rep(j,1,N) T.add(c[j]-'a',i);
            }
            T.DFS();
            rep(i,1,19) rep(j,2,T.cnt) f[j][i]=f[f[j][i-1]][i-1];
            scanf("%d",&Q);
            while(Q--) solve();
            return 0;
        }
    View Code

    稍微优化一下,为了省空间和时间,也可以手动插入S,即S没有必要插入SAM中。

    #include<bits/stdc++.h>
    #define rep2(i,a,b) for(int i=a;i>=b;i--)
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=510010;
    char c[maxn],t[maxn];
    int rt[maxn],pos[maxn],fcy[maxn],N,M,Q,tot;
    int f[maxn][20],ans,num;
    struct in{
        int L,R,Mx,id;
    }s[maxn*40];
    void update(int now)
    {
        if(s[s[now].L].Mx>=s[s[now].R].Mx) {
            s[now].Mx=s[s[now].L].Mx;
            s[now].id=s[s[now].L].id;
        }
        else {
            s[now].Mx=s[s[now].R].Mx;
            s[now].id=s[s[now].R].id;
        }
    }
    void ins(int &now,int L,int R,int p)
    {
        if(!now) now=++tot;
        if(L==R){  s[now].Mx++; s[now].id=L; return ;}
        int Mid=(L+R)>>1;
        if(p<=Mid) ins(s[now].L,L,Mid,p);
        else ins(s[now].R,Mid+1,R,p);
        update(now);
    }
    void merge(int &now,int x,int y,int L,int R)
    {
        if(!x||!y) { now= x|y; return ;}
        now=++tot;int Mid=(L+R)>>1;
        if(L==R) { s[now].Mx=s[x].Mx+s[y].Mx; s[now].id=L; return ;}
        merge(s[now].L,s[x].L,s[y].L,L,Mid);
        merge(s[now].R,s[x].R,s[y].R,Mid+1,R);
        update(now);
    }
    void query(int Now,int L,int R,int l,int r)
    {
        if(!Now||l>r) return ;
        if(s[Now].Mx<num) return ;
        if(l<=L&&r>=R) {
            if(s[Now].Mx>num) num=s[Now].Mx,ans=s[Now].id;
            else if(s[Now].Mx==num&&num!=0) ans=min(ans,s[Now].id);
            return ;
        }
        int Mid=(L+R)>>1;
        if(l<=Mid) query(s[Now].L,L,Mid,l,r);
        if(r>Mid) query(s[Now].R,Mid+1,R,l,r);
    }
    struct SAM{
        int ch[maxn][26],fa[maxn],maxlen[maxn],cnt,last;
        int a[maxn],b[maxn];
        void init()
        {
            cnt=last=1;
            memset(ch[1],0,sizeof(ch[1]));
        }
        void add(int x,int id)
        {
            int np=++cnt,p=last; last=np;
            if(id>0) ins(rt[np],1,M,id);
            maxlen[np]=maxlen[p]+1; memset(ch[np],0,sizeof(ch[np]));
            while(p&&!ch[p][x]) ch[p][x]=np,p=fa[p];
            if(!p) fa[np]=1;
            else {
                int q=ch[p][x];
                if(maxlen[q]==maxlen[p]+1) fa[np]=q;
                else {
                   int nq=++cnt; maxlen[nq]=maxlen[p]+1;
                   fa[nq]=fa[q]; fa[q]=fa[np]=nq;
                   memcpy(ch[nq],ch[q],sizeof(ch[q]));
                    while(p&&ch[p][x]==q) ch[p][x]=nq,p=fa[p];
                }
            }
        }
        vector<int>G[maxn];
        void dfs(int u)
        {
            for(int i=0;i<G[u].size();i++){
                int v=G[u][i];
                f[v][0]=u; dfs(v);
                merge(rt[u],rt[u],rt[v],1,M);
            }
        }
        void DFS()
        {
            rep(i,2,cnt) G[fa[i]].push_back(i);
            dfs(1);
        }
    }T;
    void solve()
    {
        int L,R,l,r,len;
        scanf("%d%d%d%d",&L,&R,&l,&r);
        len=r-l+1;
        int now=pos[r];
        if(fcy[r]<len) {
            printf("%d %d
    ",L,0);
            return ;
        }
        for(int i=19;i>=0;i--)
            if(T.maxlen[f[now][i]]>=len) now=f[now][i];
        ans=L; num=0;
        query(rt[now],1,M,L,R);
        printf("%d %d
    ",ans,num);
    }
    int main()
    {
        T.init();
        scanf("%s",t+1);
        scanf("%d",&M);
        rep(i,1,M) {
            T.last=1;
            scanf("%s",c+1); N=strlen(c+1);
            rep(j,1,N) T.add(c[j]-'a',i);
        }
        int now=1,len=0; N=strlen(t+1);
        rep(i,1,N) {
            int x=t[i]-'a';
            if(T.ch[now][x]) now=T.ch[now][x],len++;
            else {
                while(now&&!T.ch[now][x]) now=T.fa[now];
                if(now==0) now=1,len=0;
                else len=T.maxlen[now]+1,now=T.ch[now][x];
            }
            pos[i]=now;
            fcy[i]=len;
        }
        T.DFS();
        rep(i,1,19) rep(j,2,T.cnt) f[j][i]=f[f[j][i-1]][i-1];
        scanf("%d",&Q);
        while(Q--) solve();
        return 0;
    }
  • 相关阅读:
    Day1_Python基础
    选择排序(java版)
    冒泡排序(java版)
    手写数据库连接池(动态代理)
    JDBC增删查改(使用配置文件)
    JDBC demo
    JSP入门&会话技术
    response实现验证码图片
    android 定制自己的日志工具
    服务的最佳实践——后台执行的定时任务
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11436485.html
Copyright © 2011-2022 走看看