zoukankan      html  css  js  c++  java
  • [NOI2018]你的名字(后缀自动机+线段树合并)

    看到题目名字去补番是种怎么样的体验

    我只会 (68) 分,打了个暴力。正解看了一会儿,发现跟 ([HEOI2016/TJOI2016]) 字符串很像,用线段树合并维护 (endpos) 集合,然后一边匹配一边记录答案。

    [ans=sum_{i=1}^{cnt}max(0,len_i-max(len_{fa_i},lim_{pos_i})) ]

    (Code Below:)

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=1000000+10;
    int n,m,q,a[maxn],b[maxn],rt[maxn],L[maxn*40],R[maxn*40],sum[maxn*40],tot;
    char s[maxn];
    
    struct SAM{
        int last,cnt,ch[maxn][26],fa[maxn],l[maxn],pos[maxn],lim[maxn];
        void init(){
            for(int i=1;i<=cnt;i++){
                for(int j=0;j<26;j++) ch[i][j]=0;
            }
            last=cnt=1;
        }
        void insert(int c,int id){
            int p=last,q=++cnt;last=q;l[q]=l[p]+1;pos[q]=id;
            for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=q;
            if(!p) fa[q]=1;
            else {
                int r=ch[p][c];
                if(l[p]+1==l[r]) fa[q]=r;
                else {
                    int s=++cnt;l[s]=l[p]+1;pos[s]=pos[r];
                    memcpy(ch[s],ch[r],sizeof(ch[r]));
                    fa[s]=fa[r];fa[r]=fa[q]=s;
                    for(;p&&ch[p][c]==r;p=fa[p]) ch[p][c]=s;
                }
            }
        }
        ll calc(){
            ll ans=0;
            for(int i=2;i<=cnt;i++) ans+=max(0,l[i]-max(l[fa[i]],lim[pos[i]]));
            return ans;
        }
    }S,T;
    
    void update(int &now,int l,int r,int x){
        if(!now) now=++tot;
        sum[now]++;
        if(l == r) return ;
        int mid=(l+r)>>1;
        if(x <= mid) update(L[now],l,mid,x);
        else update(R[now],mid+1,r,x);
    }
    
    int merge(int x,int y){
        if(x==0||y==0) return x+y;
        int z=++tot;
        sum[z]=sum[x]+sum[y];
        L[z]=merge(L[x],L[y]);
        R[z]=merge(R[x],R[y]);
        return z;
    }
    
    int query(int now,int Le,int Ri,int l,int r){
        if(!now||Le>Ri) return 0;
        if(Le <= l && r <= Ri) return sum[now];
        int mid=(l+r)>>1,ans=0;
        if(Le <= mid) ans+=query(L[now],Le,Ri,l,mid);
        if(Ri > mid) ans+=query(R[now],Le,Ri,mid+1,r);
        return ans;
    }
    
    int main()
    {
        scanf("%s",s+1);n=strlen(s+1);S.init();
        for(int i=1;i<=n;i++){
            S.insert(s[i]-'a',i);
            update(rt[S.last],1,n,i);
        }
        for(int i=1;i<=S.cnt;i++) b[S.l[i]]++;
        for(int i=1;i<=S.cnt;i++) b[i]+=b[i-1];
        for(int i=S.cnt;i>=1;i--) a[b[S.l[i]]--]=i;
        for(int i=S.cnt;i>=2;i--) rt[S.fa[a[i]]]=merge(rt[S.fa[a[i]]],rt[a[i]]);
        scanf("%d",&q);
        int l,r,p,c,len;
        while(q--){
            scanf("%s%d%d",s+1,&l,&r);m=strlen(s+1);
            T.init();len=0;p=1;
            for(int i=1;i<=m;i++){
                c=s[i]-'a';T.insert(c,i);
                while(1){
                    if(S.ch[p][c]&&query(rt[S.ch[p][c]],l+len,r,1,n)){
                        len++;p=S.ch[p][c];
                        break;
                    }
                    if(len==0) break;
                    if(--len==S.l[S.fa[p]]) p=S.fa[p];
                }
                T.lim[i]=len;
            }
            printf("%lld
    ",T.calc());
        }
        return 0;
    }
    
  • 相关阅读:
    存储型 XSS 原理复现
    反射型 XSS 原理复现
    HTTP 简易理解
    Markdown 流程图语法
    Dirsearch 快速开始
    sqlmap 快速开始
    SQL 注入原理
    XSS 原理
    51nod 1835 完全图
    11.5 AM 请求
  • 原文地址:https://www.cnblogs.com/owencodeisking/p/10226034.html
Copyright © 2011-2022 走看看