zoukankan      html  css  js  c++  java
  • Codeforces 666E Forensic Examination

    题意:给定主串s和m个模式串,每次询问[l,r]的模式串中出现s[pl...pr]次数最多的串和次数。

    这题挺简单的,先把所有模式串拿来建广义后缀自动机,询问相当于子树众数,用线段树合并即可。

    那我为什么写这题题解呢?

    1.作为我博客第一道非BZOJ题。

    2.作为我博客第一道写题意(英文)的题。

    3.这题是老师留的作业,所以可以骗访问量。

    4.记录一下广义后缀自动机的优秀写法,以前我是无脑建的。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define l(x) t[x].l
    #define r(x) t[x].r
    #define M ((L+R)>>1)
    
    typedef pair<int,int> pr;
    const int S=500005,N=100005;
    char s[N],sr[S];
    int m,e,q,l1,r1,l2,r2,ls,sz,tt,po[S],ln[S],l[N],f[N],ch[N][26],hd[N],nx[N],to[N],rt[N],fa[N][21];
    struct nd {int l,r; pr p;}t[N*30];
    void ad(int x,int y) {to[++e]=y,nx[e]=hd[x],hd[x]=e;}
    
    void ins(int c) {
        int u=ls,x=ch[u][c];
        if(x) {
            if(l[u]+1==l[x]) {ls=x; return;}
            l[++sz]=l[u]+1,f[sz]=f[x],f[x]=sz,ls=sz;
            for(int j=0;j<26;j++) ch[sz][j]=ch[x][j];
            for(;u&&ch[u][c]==x;u=f[u]) ch[u][c]=sz;
            if(ch[u][c]==x) ch[u][c]=sz;
        } else {
            for(ls=++sz,l[sz]=l[u]+1;u&&!ch[u][c];u=f[u]) ch[u][c]=sz;
            int x=ch[u][c];
            if(!x) {ch[u][c]=sz; return;}
            if(l[u]+1==l[x]) {f[sz]=x; return;}
            l[++sz]=l[u]+1,f[sz]=f[x],f[x]=f[ls]=sz;
            for(int j=0;j<26;j++) ch[sz][j]=ch[x][j];
            for(;u&&ch[u][c]==x;u=f[u]) ch[u][c]=sz;
            if(ch[u][c]==x) ch[u][c]=sz;
        }
    }
    
    void pu(int x) {t[x].p=max(t[l(x)].p,t[r(x)].p);}
    int mrg(int x,int y,int L=1,int R=m) {
        if(!x||!y) return x|y;
        int z=++tt;
        if(L==R) {t[z].p=make_pair(t[x].p.first+t[y].p.first,-L); return z;}
        l(z)=mrg(l(x),l(y),L,M),r(z)=mrg(r(x),r(y),M+1,R),pu(z);
        return z;
    }
    void upd(int &x,int v,int L=1,int R=m) {
        if(!x) x=++tt;
        if(L==R) {t[x].p=make_pair(t[x].p.first+1,-v); return;}
        if(v<=M) upd(l(x),v,L,M); else upd(r(x),v,M+1,R);
        pu(x);
    }
    pr qr(int x,int l,int r,int L=1,int R=m) {
        if(!x) return make_pair(0,0);
        if(l<=L&&r>=R) return t[x].p;
        if(r<=M) return qr(l(x),l,r,L,M); if(l>M) return qr(r(x),l,r,M+1,R);
        return max(qr(l(x),l,r,L,M),qr(r(x),l,r,M+1,R));
    }
    
    int gt(int x,int ln) {for(int i=20;~i;i--) if(l[fa[x][i]]>=ln) x=fa[x][i]; return x;}
    void dfs(int x) {for(int i=hd[x];i;i=nx[i]) dfs(to[i]),rt[x]=mrg(rt[x],rt[to[i]]),fa[to[i]][0]=x;}
    
    int main() {
        scanf("%s%d",sr,&m);
        for(int i=1;i<=m;i++) {
            scanf("%s",s),ls=0;
            for(int j=0;s[j];j++) ins(s[j]-'a'),upd(rt[ls],i);
        }
        for(int i=0,u=0,s=0;sr[i];i++) {
            int c=sr[i]-'a';
            while(u&&!ch[u][c]) u=f[u],s=l[u];
            if(ch[u][c]) ln[i+1]=++s,u=ch[u][c],po[i+1]=u;
        }
        for(int i=1;i<=sz;i++) ad(f[i],i);
        dfs(0),scanf("%d",&q);
        for(int j=1;j<21;j++) for(int i=1;i<=sz;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
        while(q--) {
            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            if(ln[r2]<r2-l2+1) {printf("%d 0
    ",l1); continue;}
            pr k=qr(rt[gt(po[r2],r2-l2+1)],l1,r1);
            if(k.first) printf("%d %d
    ",-k.second,k.first); else printf("%d 0
    ",l1);
        }
        return 0;
    }
  • 相关阅读:
    第5次作业
    第六次作业
    第五次作业
    软件需求最佳实践阅读笔记05
    软件需求最佳实践阅读笔记04
    构建民航知识图谱
    软件需求最佳实践阅读笔记03
    软件需求最佳实践阅读笔记02
    软件需求最佳实践阅读笔记01
    程序员的自我修养阅读笔记03
  • 原文地址:https://www.cnblogs.com/juruolty/p/7061440.html
Copyright © 2011-2022 走看看