zoukankan      html  css  js  c++  java
  • [BZOJ1396]识别子串 后缀自动机+线段树

    1396: 识别子串

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 451  Solved: 290
    [Submit][Status][Discuss]

    Description

    Input

    一行,一个由小写字母组成的字符串S,长度不超过10^5

    Output

    L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

    Sample Input

    agoodcookcooksgoodfood

    Sample Output

    1
    2
    3
    3
    2
    2
    3
    3
    2
    2
    3
    3
    2
    1
    2
    3
    3
    2
    1
    2
    3
    4

    HINT

     

    Source

    首先我们发现要找子串,想到用后缀自动机。

    显然只出现一次的子串为right=1的节点(即结束节点只有一个)。对于这些节点,我们考虑对答案的贡献。

    对于一个节点显然endpos-maxlen+1到endpos-minlen+1的子串是唯一的贡献为endpos-i+1。

    对于endpos-minlen+1到endpos的节点,子串不唯一,我们需要将他向前延伸到endpos-minlen+1的点,贡献为minlen。

    维护两棵线段树即可。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<algorithm>
     7 #define maxn 800005
     8 using namespace std;
     9 struct data {
    10     int son[maxn][30],link[maxn],step[maxn],cnt,last;
    11     int v[maxn],pos[maxn],size[maxn],endpos[maxn];
    12     data() {last=cnt=1;}
    13     void extend(int c,int x) {
    14         int p=last,np=last=++cnt;
    15         step[np]=step[p]+1;size[np]=1;endpos[np]=x;
    16         while(p&&!son[p][c]) son[p][c]=np,p=link[p];
    17         if(!p) link[np]=1;
    18         else {
    19             int q=son[p][c];
    20             if(step[q]==step[p]+1) link[np]=q;
    21             else {
    22                 int nq=++cnt;
    23                 memcpy(son[nq],son[q],sizeof(son[q]));
    24                 link[nq]=link[q];
    25                 link[q]=link[np]=nq;
    26                 step[nq]=step[p]+1;
    27                 while(son[p][c]==q&&p) son[p][c]=nq,p=link[p];
    28             }
    29         }
    30     }
    31     void pre() {
    32         for(int i=1;i<=cnt;i++) v[step[i]]++;
    33         for(int i=1;i<=cnt;i++) v[i]+=v[i-1];
    34         for(int i=cnt;i;i--) pos[v[step[i]]--]=i;
    35         for(int i=cnt;i;i--) {
    36             int x=pos[i];
    37             size[link[x]]+=size[x];
    38             endpos[link[x]]=max(endpos[link[x]],endpos[x]);
    39         } 
    40     }
    41     struct tmp{
    42         int minx[maxn],tag[maxn];
    43         tmp(){memset(minx,97,sizeof(minx));for(int i=1;i<maxn;i++) tag[i]=2147483647;}
    44         void pushup(int o) {
    45             int ls=o<<1,rs=ls+1;
    46             minx[o]=min(minx[ls],minx[rs]);
    47         }
    48         void pushdown(int o) {
    49             int ls=o<<1,rs=ls+1;
    50             minx[ls]=min(tag[o],minx[ls]);minx[rs]=min(minx[rs],tag[o]);
    51             tag[ls]=min(tag[ls],tag[o]);tag[rs]=min(tag[rs],tag[o]);
    52             tag[o]=2147483647;
    53         }
    54         void update(int l,int r,int o,int L,int R,int val) {
    55             pushdown(o);
    56             if(L<=l&&R>=r) {tag[o]=min(tag[o],val);minx[o]=min(minx[o],val);return;}
    57             int mid=l+r>>1,ls=o<<1,rs=ls+1;
    58             if(L<=mid)update(l,mid,ls,L,R,val);
    59             if(R>mid) update(mid+1,r,rs,L,R,val);
    60             pushup(o);
    61         }
    62         int query(int l,int r,int o,int x) {
    63             pushdown(o);
    64             if(l==r) return minx[o];
    65             int mid=l+r>>1,ls=o<<1,rs=ls+1;
    66             if(x<=mid) return query(l,mid,ls,x);
    67             if(x>mid) return query(mid+1,r,rs,x);
    68         }
    69     }t1,t2;
    70     void work(int x) {
    71         for(int i=1;i<=cnt;i++) {
    72             if(size[i]!=1) continue;
    73             int maxlen=step[i],minlen=step[link[i]]+1;
    74             t1.update(1,x,1,endpos[i]-maxlen+1,endpos[i]-minlen+1,endpos[i]+1);
    75             t2.update(1,x,1,endpos[i]-minlen+1,endpos[i],minlen);
    76         }
    77         for(int i=1;i<=x;i++) {
    78             int a1=t1.query(1,x,1,i)-i,a2=t2.query(1,x,1,i);
    79             printf("%d
    ",min(a1,a2));
    80         }
    81     }
    82 }sam;
    83 char ch[maxn];
    84 int main() {
    85     scanf("%s",ch+1);
    86     int len=strlen(ch+1);
    87     for(int i=1;i<=len;i++) sam.extend(ch[i]-'a',i);
    88     sam.pre();
    89     sam.work(len);
    90 } 
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    Codeforces 653C Bear and Up-Down【暴力】
    Codeforces 653B Bear and Compressing【DFS】
    Codeforces 653B Bear and Compressing【DFS】
    Codeforces 653A Bear and Three Balls【水题】
    Codeforces 645D Robot Rapping Results Report【拓扑排序+二分】
    Codeforces 645C Enduring Exodus【二分】
    软件工程作业01
    《构建之法》阅读笔记5
    登录界面代码
    《构建之法》读书笔记4
  • 原文地址:https://www.cnblogs.com/wls001/p/8253481.html
Copyright © 2011-2022 走看看