• 【NOI2018】你的名字


    题面

    https://www.luogu.org/problem/P4770

    题解

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #define ri register int
    #define LL long long
    #define nlogn 60500000
    #define M 1000050
    using namespace std;
    
    int n,L0,L1,l,r;
    char s[M],t[M];
    int mat[M];
    int ff[M<<1],ch[M<<1][26],len[M<<1];
    int root[M<<1];
    
    struct SegmentTree {
      int ch[nlogn][2],tot;
      int newnode() {
        return ++tot;
      }
      void insert(int &x,int k,int l,int r){
        if (!x) x=++tot;
        if (l==r) return;
        int mid=(l+r)/2;
        if (k<=mid) insert(ch[x][0],k,l,mid); else insert(ch[x][1],k,mid+1,r);
      }
      bool have(int x,int lb,int rb,int lc,int rc) {
        if (!x) return false;
        if (lb>rc || rb<lc) return 0;
        if (lc<=lb && rb<=rc) return 1;
        int mid=(lb+rb)/2;
        return have(ch[x][0],lb,mid,lc,rc)|have(ch[x][1],mid+1,rb,lc,rc);
      }
      int merge(int x,int y){
        if (!x || !y) return x|y;
        int ret=++tot;
        ch[ret][0]=merge(ch[x][0],ch[y][0]);
        ch[ret][1]=merge(ch[x][1],ch[y][1]);
        return ret;
      }
      int refind(int now,int lb,int rb) {
        if (lb==rb) return lb;
        if (!now) return -1;
        int mid=(lb+rb)/2;
        if (ch[now][0]) return refind(ch[now][0],lb,mid); else return refind(ch[now][1],mid+1,rb);
      }
      int find(int now,int lb,int rb,int l,int r) {
        if (lb>r || rb<l || !now) return -1;
        if (l<=lb && rb<=r) return refind(now,lb,rb);
        int mid=(lb+rb)/2,t=find(ch[now][0],lb,mid,l,r);
        if (t!=-1) return t; else return find(ch[now][1],mid+1,rb,l,r);
      }
    } segt;
    
    vector<int> som[M<<1];
    struct SuffixAutoMato {
      int las,tot;
      void init() {
        las=tot=1;
      }
      void extend(int c) {
        int p=las,np=++tot; las=tot;
        len[np]=len[p]+1; segt.insert(root[np],len[np],1,L0);
        while (p && ch[p][c]==0) ch[p][c]=np,p=ff[p];
        if (!p) ff[np]=1;
        else {
          int q=ch[p][c];
          if (len[p]+1==len[q]) ff[np]=q;
          else {
            int nq=++tot;
            for (ri i=0;i<26;i++) ch[nq][i]=ch[q][i]; ff[nq]=ff[q];
            len[nq]=len[p]+1;
            ff[np]=ff[q]=nq;
            while (p && ch[p][c]==q) ch[p][c]=nq,p=ff[p];
          }
        }
      }
      void maketree() {
        for (ri i=1;i<=tot;i++) som[ff[i]].push_back(i);
      }
      void dp(int x) {
        for (ri i=0;i<som[x].size();i++) {
          dp(som[x][i]);
          root[x]=segt.merge(root[x],root[som[x][i]]);
        }
      }
    } sam;
    
    
    struct SuffixTree {
      int ff[M<<1],ch[M<<1][26],len[M<<1];
      int las,tot;
      int vis[M<<1],poi[M];
      vector<int> son[M<<1];
      void init() {
        for (ri i=1;i<=tot;i++) for (ri j=0;j<26;j++) ch[i][j]=0;
        for (ri i=1;i<=tot;i++) ff[i]=len[i]=vis[i]=0;
        for (ri i=1;i<=tot;i++) son[i].clear();
        las=tot=1;
      }
      void dp(int x) {
        for (ri i=0;i<son[x].size();i++) {
          dp(son[x][i]);
          if (vis[son[x][i]]>vis[x]) vis[x]=vis[son[x][i]];
        }
      }
      LL query() {
        for (ri i=1;i<=L1;i++) vis[poi[i]]=mat[i];
        for (ri i=1;i<=tot;i++) son[ff[i]].push_back(i);
        dp(1);
        LL ret=0LL;
        for (ri i=1;i<=tot;i++) ret+=min(max(len[i]-vis[i],0),len[i]-len[ff[i]]);
        init();
        return ret;
      }
      void extend(int c) {
        int p=las,np=++tot; las=tot;
        len[np]=len[p]+1; poi[len[np]]=tot;
        while (p && ch[p][c]==0) ch[p][c]=np,p=ff[p];
        if (!p) ff[np]=1;
        else {
          int q=ch[p][c];
          if (len[p]+1==len[q]) ff[np]=q;
          else {
            int nq=++tot;
            for (ri i=0;i<26;i++) ch[nq][i]=ch[q][i]; ff[nq]=ff[q];
            len[nq]=len[p]+1;
            ff[np]=ff[q]=nq;
            while (p && ch[p][c]==q) ch[p][c]=nq,p=ff[p];
          }
        }
      }
    } st;
    
    int main(){
      scanf("%s",s+1);
      L0=strlen(s+1);
      sam.init(); 
      for (ri i=1;i<=L0;i++) sam.extend(s[i]-'a');
      sam.maketree(); sam.dp(1);
      scanf("%d",&n);
      st.las=st.tot=1;
      while (n--) {
        scanf("%s %d %d",t+1,&l,&r);
        L1=strlen(t+1);
        for (ri i=1;i<=L1;i++) st.extend(t[i]-'a');
        int now=1,cc=0;
        for (ri i=1;i<=L1;i++) {
          if (ch[now][t[i]-'a']) now=ch[now][t[i]-'a'],cc++;
          else {
            while (now && !ch[now][t[i]-'a']) now=ff[now];
            if (!now) now=1,cc=0; else cc=len[now]+1,now=ch[now][t[i]-'a'];
          }
          bool skip=0;
          while (now && !segt.have(root[now],1,L0,l+len[ff[now]],r)) skip=1,now=ff[now],cc=len[now];
          if (!now) now=1,mat[i]=cc=0;
          else {
            if (!skip) {
              if (!segt.have(root[now],1,L0,l+len[now]-1,r)) {
                int Lb=segt.find(root[now],1,L0,l+len[ff[now]],r);
                mat[i]=Lb-l+1;
                if (Lb-l+1>=cc) mat[i]=cc; else mat[i]=cc=Lb-l+1;
              }
              else mat[i]=cc;
            }
            else if (segt.have(root[now],1,L0,l+len[now]-1,r)) mat[i]=cc=len[now];
            else {
              int Lb=segt.find(root[now],1,L0,l+len[ff[now]],r);
              mat[i]=cc=Lb-l+1;
            }
          }
        }
        printf("%lld
    ",st.query());
      }
    }
  • 相关阅读:
    .NET开源项目
    关于微信号的校验
    java 中关于synchronized的通常用法
    关于java 定时器的使用总结
    新的博客已经启用,欢迎大家访问(402v.com)
    Hadoop综合大作业
    hive基本操作与应用
    理解MapReduce计算构架
    熟悉HBase基本操作
    第三章 熟悉常用的HDFS操作
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11279364.html
Copyright © 2020-2023  润新知