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\n",last);
        }
    }
    void debug(void){
        for(int i=1;i<=Nodecnt;i++){
           printf("%d: maxlen=%d suflink=%d\n",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\n",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\n",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\n",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\n",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\n",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\n",tmpp);
        }
    }
    dfs(1);
    for(int i=1;i<=q;i++){
        if(Q[i].times)
            printf("%d %d\n",Q[i].which,Q[i].times);
        else
            printf("%d %d\n",Q[i].l,Q[i].times);
    }
    return 0;
}
posted @ 2019-04-17 17:10  dreagonm  阅读(182)  评论(0编辑  收藏  举报