zoukankan      html  css  js  c++  java
  • CF666E Forensic Examination

    思路

    线段树合并+广义SAM

    先把所有串都插入SAM中,然后用线段树合并维护right集合,对S匹配的同时离线询问,然后就好啦

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int MAXN = 100100;
    const int MAXlog = 20;
    char s[500500],t[50500];
    int lens,m,q;
    namespace Segment_Tree{
        int Nodecnt=0,root[100100];
        struct Node{
            int lson,rson,maxx,maxnum;
        }Seg[100100*50];
        void pushup(int o){
            if(Seg[Seg[o].lson].maxx>Seg[Seg[o].rson].maxx){
                Seg[o].maxx=Seg[Seg[o].lson].maxx;
                Seg[o].maxnum=Seg[Seg[o].lson].maxnum;
            }
            else if(Seg[Seg[o].rson].maxx>Seg[Seg[o].lson].maxx){
                Seg[o].maxx=Seg[Seg[o].rson].maxx;
                Seg[o].maxnum=Seg[Seg[o].rson].maxnum;
            }
            else if(Seg[Seg[o].rson].maxx==Seg[Seg[o].lson].maxx){
                if(Seg[Seg[o].lson].maxnum<Seg[Seg[o].rson].maxnum){
                    Seg[o].maxx=Seg[Seg[o].lson].maxx;
                    Seg[o].maxnum=Seg[Seg[o].lson].maxnum;
                }
                else{
                    Seg[o].maxx=Seg[Seg[o].rson].maxx;
                    Seg[o].maxnum=Seg[Seg[o].rson].maxnum;
                }
            }
        }
        void merge(int l,int r,int &lroot,int rroot){// rroot -> lroot
            if(lroot*rroot==0){
                lroot=lroot+rroot;
                return;
            }
            if(l==r){
                Seg[lroot].maxx+=Seg[rroot].maxx;
                Seg[lroot].maxnum=l;
                return; 
            }
            int mid=(l+r)>>1;
            merge(l,mid,Seg[lroot].lson,Seg[rroot].lson);
            merge(mid+1,r,Seg[lroot].rson,Seg[rroot].rson);
            pushup(lroot);
        }
        void add(int l,int r,int pos,int &o){
            if(!o)
                o=++Nodecnt;
            if(l==r){
                Seg[o].maxx++;
                Seg[o].maxnum=pos;
                return;
            }
            int mid=(l+r)>>1;
            if(pos<=mid)
                add(l,mid,pos,Seg[o].lson);
            else
                add(mid+1,r,pos,Seg[o].rson);
            pushup(o);
        }
        Node query(int L,int R,int l,int r,int o){
            if(!o)
                return (Node){0,0,0,L};
            if(L<=l&&r<=R)
                return Seg[o];
            int mid=(l+r)>>1;
            if(R<=mid)
                return query(L,R,l,mid,Seg[o].lson);
            else{
                if(L>mid)
                    return query(L,R,mid+1,r,Seg[o].rson);
                else{
                    Node ans,lx=query(L,R,l,mid,Seg[o].lson),rx=query(L,R,mid+1,r,Seg[o].rson);
                    if(lx.maxx>rx.maxx){
                        ans.maxx=lx.maxx;
                        ans.maxnum=lx.maxnum;
                    }
                    else if(rx.maxx>lx.maxx){
                        ans.maxx=rx.maxx;
                        ans.maxnum=rx.maxnum;    
                    }
                    else{
                        if(lx.maxnum<rx.maxnum){
                            ans.maxx=lx.maxx;
                            ans.maxnum=lx.maxnum;
                        }
                        else{
                            ans.maxx=rx.maxx;
                            ans.maxnum=rx.maxnum;
                        }
                    }
                    return ans;
                }
            }
        }
    }
    namespace SAM{
        int Nodecnt=1,trans[MAXN][26],maxlen[MAXN],suflink[MAXN];
        int New_state(int _maxlen,int *_trans,int _suflink){
            ++Nodecnt;
            maxlen[Nodecnt]=_maxlen;
            if(_trans)
                for(int i=0;i<26;i++)
                    trans[Nodecnt][i]=_trans[i];
            suflink[Nodecnt]=_suflink;
            return Nodecnt;
        }
        int add_len(int u,int c){
            if(trans[u][c]){
                int v=trans[u][c];
                if(maxlen[v]==maxlen[u]+1)
                    return v;
                int y=New_state(maxlen[u]+1,trans[v],suflink[v]);
                suflink[v]=y;
                while(u&&trans[u][c]==v){
                    trans[u][c]=y;
                    u=suflink[u];
                }            
                return y;
            }
            else{
                int z=New_state(maxlen[u]+1,NULL,0);
                while(u&&trans[u][c]==0){
                    trans[u][c]=z;
                    u=suflink[u];
                }
                if(!u){
                    suflink[z]=1;
                    return z;
                }
                int v=trans[u][c];
                if(maxlen[v]==maxlen[u]+1){
                    suflink[z]=v;
                    return z;
                }
                int y=New_state(maxlen[u]+1,trans[v],suflink[v]);
                suflink[v]=suflink[z]=y;
                while(u&&trans[u][c]==v){
                    trans[u][c]=y;
                    u=suflink[u];
                }            
                return z;
            }
        }
        void insert(char *s,int len,int inq){
            int last=1;
            for(int i=1;i<=len;i++){
                last=add_len(last,s[i]-'a');
                Segment_Tree::add(1,m,inq,Segment_Tree::root[last]);
                // printf("o=%d
    ",last);
            }
        }
        void debug(void){
            for(int i=1;i<=Nodecnt;i++){
               printf("%d: maxlen=%d suflink=%d
    ",i,maxlen[i],suflink[i]); 
            }
        }   
    }
    namespace parent_tree{
        int fir[100100],v[100100],nxt[100100],cnt,fa[100100][MAXlog];
        void addedge(int ui,int vi){
            ++cnt;
            v[cnt]=vi;
            nxt[cnt]=fir[ui];
            fir[ui]=cnt;
        }
        void build(void){
            for(int i=2;i<=SAM::Nodecnt;i++){
                addedge(SAM::suflink[i],i);
                fa[i][0]=SAM::suflink[i];
            }
        }
        void pre(void){
            build();
            for(int i=1;i<MAXlog;i++){
                for(int j=1;j<=SAM::Nodecnt;j++)
                    fa[j][i]=fa[fa[j][i-1]][i-1];
            }
        }
        void debug(void){
            for(int i=0;i<16;i++){
                for(int j=1;j<=SAM::Nodecnt;j++)
                    printf("fa[%d][%d]=%d
    ",j,i,fa[j][i]);
            }
        }
    }
    struct Ask{
        int l,r,pl,pr,which,times;
    }Q[500500];
    struct table{
        int fir[500500],v[500500],nxt[500500],cnt;
        void add(int u,int num){
            ++cnt;
            v[cnt]=num;
            nxt[cnt]=fir[u];
            fir[u]=cnt;
        }
    }Qr,QN;
    void dfs(int u){
        for(int i=parent_tree::fir[u];i;i=parent_tree::nxt[i]){
            dfs(parent_tree::v[i]);
            Segment_Tree::merge(1,m,Segment_Tree::root[u],Segment_Tree::root[parent_tree::v[i]]);
        }
        for(int i=QN.fir[u];i;i=QN.nxt[i]){
            int o=QN.v[i];
            // printf("id=%d
    ",o);
            Segment_Tree::Node tmp=Segment_Tree::query(Q[o].l,Q[o].r,1,m,Segment_Tree::root[u]);
            Q[o].which=tmp.maxnum;
            Q[o].times=tmp.maxx;
            // printf("which=%d time=%d
    ",Q[o].which,Q[o].times);
        }
    }
    int main(){
        // freopen("test.in","r",stdin);
        // freopen("test.out","w",stdout);
        scanf("%s",s+1);
        lens=strlen(s+1);
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%s",t+1);
            SAM::insert(t,strlen(t+1),i);
        }
        // SAM::debug();
        parent_tree::pre();
        // parent_tree::debug();
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%d %d %d %d",&Q[i].l,&Q[i].r,&Q[i].pl,&Q[i].pr);
            Qr.add(Q[i].pr,i);
        }
        int nowlen=0,nowp=1;
        for(int i=0;i<lens;i++){
            // printf("i=%d nowp=%d len=%d
    ",i+1,nowp,nowlen);
            if(SAM::trans[nowp][s[i+1]-'a']){
                nowp=SAM::trans[nowp][s[i+1]-'a'];
                nowlen++;
            }
            else{
                while(nowp&&(SAM::trans[nowp][s[i+1]-'a']==0))
                    nowp=SAM::suflink[nowp];
                if(!nowp){
                    nowp=1;
                    nowlen=0;
                    continue;
                }
                nowlen=SAM::maxlen[nowp]+1;
                nowp=SAM::trans[nowp][s[i+1]-'a'];
            }
            for(int j=Qr.fir[i+1];j;j=Qr.nxt[j]){
                // printf("id=%d
    ",Qr.v[j]);
                int lentmp=Q[Qr.v[j]].pr-Q[Qr.v[j]].pl+1;
                if(nowlen<lentmp)
                    continue;
                int tmpp=nowp;
                for(int k=MAXlog-1;k>=0;k--)
                    if(SAM::maxlen[parent_tree::fa[tmpp][k]]>=lentmp)
                        tmpp=parent_tree::fa[tmpp][k];
                QN.add(tmpp,Qr.v[j]);
                // printf("getNode=%d
    ",tmpp);
            }
        }
        dfs(1);
        for(int i=1;i<=q;i++){
            if(Q[i].times)
                printf("%d %d
    ",Q[i].which,Q[i].times);
            else
                printf("%d %d
    ",Q[i].l,Q[i].times);
        }
        return 0;
    }
    
  • 相关阅读:
    [NOI2003],[AHOI2006]文本编辑器
    luogu P5151 HKE与他的小朋友
    [NOI2005]维护数列
    [HNOI2012]永无乡
    luogu P4146 序列终结者
    [SCOI2016]美味
    UVA1451 Average
    [JSOI2007]字符加密
    luogu P3809 【模板】后缀排序
    CentOS 7系统启动后怎么从命令行模式切换到图形界面模式
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10724796.html
Copyright © 2011-2022 走看看