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

    题目描述

    给你一个串S以及一个字符串数组T[1..m]q次询问,每次问S的子串S[pl..pr]在T[l..r]中的哪个串里的出现次数最多,并输出出现次数。

    如有多解输出最靠前的那一个。

    题解

    算是道字符串比较套路的题吧。

    对模式串建SAM,对所有模式串的所有前缀维护right集合。

    然后对于每个询问,倍增找到关键点,查子树众数。

    坑:在最匹配串做匹配的时候,要记录匹配长度,如果匹配长度不够询问长度,直接判无解。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define N 1000009
    using namespace std;
    typedef long long ll;
    int ch[N][26],tott,tr[N*32],id[N*32],ls[N*32],rs[N*32],ans1,ans2,fa[N],mat[N];
    int cnt,last,l[N],tot,head[N],n,p[21][N],deep[N],T[N],tag[N];
    char s[N],s1[N];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    void upd(int &cnt,int l,int r,int x){
        if(!cnt)cnt=++tott;
        if(l==r){tr[cnt]++;id[cnt]=l;return;}
        int mid=(l+r)>>1;
        if(mid>=x)upd(ls[cnt],l,mid,x);
        else upd(rs[cnt],mid+1,r,x);
        tr[cnt]=max(tr[ls[cnt]],tr[rs[cnt]]);
        id[cnt]=tr[ls[cnt]]>=tr[rs[cnt]]?id[ls[cnt]]:id[rs[cnt]];
    }
    int merge(int x,int y,int l,int r){
        if(!x||!y)return x^y;
        int p=++tott;
        if(l==r){tr[p]=tr[x]+tr[y];id[p]=l;return p;}
        int mid=(l+r)>>1;
        ls[p]=merge(ls[x],ls[y],l,mid);rs[p]=merge(rs[x],rs[y],mid+1,r);
        tr[p]=max(tr[ls[p]],tr[rs[p]]);
        id[p]=tr[ls[p]]>=tr[rs[p]]?id[ls[p]]:id[rs[p]];
        return p;
    }
    void query(int cnt,int l,int r,int L,int R){
        if(!cnt)return;
        if(l>=L&&r<=R){
            if(tr[cnt]>ans1){
                ans1=tr[cnt];
                ans2=id[cnt];
            }
            return;
        } 
        int mid=(l+r)>>1;
        if(mid>=L)query(ls[cnt],l,mid,L,R);
        if(mid<R)query(rs[cnt],mid+1,r,L,R);
    }
    inline void ins(int x,int id){
        if(ch[last][x]){
            int p=last,q=ch[last][x];
            if(l[p]+1==l[q])last=q;
            else{
                int nq=++cnt;l[nq]=l[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[nq]));
                fa[nq]=fa[q];fa[q]=nq;
                for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
                last=nq;
            }
        }
        else{
            int p=last,np=++cnt;l[np]=l[p]+1;last=np;
            for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
            if(!p)fa[np]=1;
            else{
              int q=ch[p][x];
              if(l[p]+1==l[q])fa[np]=q;
              else{
                  int nq=++cnt;l[nq]=l[p]+1;
                  memcpy(ch[nq],ch[q],sizeof(ch[nq]));
                  fa[nq]=fa[q];fa[q]=fa[np]=nq;
                  for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
              }    
            }
        }
        upd(T[last],1,n,id);
    }
    struct edge{int n,to;}e[N];
    inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
    void dfs(int u){
        for(int i=1;(1<<i)<=deep[u];++i)p[i][u]=p[i-1][p[i-1][u]];
        for(int i=head[u];i;i=e[i].n){
            int v=e[i].to;deep[v]=deep[u]+1;p[0][v]=u;
            dfs(v);T[u]=merge(T[u],T[v],1,n);
        }
    }
    int main(){
        scanf("%s",s+1);
        n=rd();cnt=1;
        for(int i=1;i<=n;++i){
            last=1;
            scanf("%s",s1);int len=strlen(s1);
            for(int j=0;j<len;++j)ins(s1[j]-'a',i);
        }
        for(int i=1;i<=cnt;++i)if(fa[i])add(fa[i],i);
        dfs(1);int len=strlen(s+1),now=1,le=0;
        for(int i=1;i<=len;++i){
            while(now&&!ch[now][s[i]-'a'])now=fa[now],le=l[now];
            if(!now)now=1;
            if(ch[now][s[i]-'a'])now=ch[now][s[i]-'a'],le++;
            tag[i]=now;mat[i]=le;
        }
        int q=rd(),l1,r1,l2,r2;
        while(q--){
            l2=rd();r2=rd();l1=rd();r1=rd();
            int x=tag[r1];
            if(!x||mat[r1]<r1-l1+1){
                printf("%d 0
    ",l2);continue;
            }
            for(int i=20;i>=0;--i)if(l[p[i][x]]>=r1-l1+1)x=p[i][x];    
        
            ans1=0;ans2=l2;;
            query(T[x],1,n,l2,r2);
            printf("%d %d
    ",ans2,ans1);
        }
        return 0;
    }
  • 相关阅读:
    微信小程序入门
    rem js相关
    移动端rem.js使用方法
    手机访问PC网站自动跳转到手机版
    当 return 遇到 try
    Ubuntu apt 使用代理
    shell 十进制数字转十六进制字符串并将结果保存到变量
    (二)一起学 Java Collections Framework 源码之 AbstractCollection
    (一)一起学 Java Collections Framework 源码之 概述
    解决 meld 出现 locale.setlocale(locale.LC_ALL,'') 失败的问题
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10422490.html
Copyright © 2011-2022 走看看