• 【SAM】bzoj5084: hashit


    做得心 力 憔 悴

    Description

    你有一个字符串S,一开始为空串,要求支持两种操作
    在S后面加入字母C
    删除S最后一个字母
    问每次操作后S有多少个两两不同的连续子串

    Input

    一行一个字符串Q,表示对S的操作
    如果第i个字母是小写字母c,表示第一种加字母c的操作
    如果为-表示删除操作,保证所有删除操作前S都非空
    |Q|<=10^5

    Output

    输出|Q|行,第i行表示i个操作之后S内有多少个不同子串

    题目分析

    陈老师神题x2,暂时只会做法一。

    做法一:暴力回退

    还是自己菜啊……这么个暴力都写了老久。

    思路就是将每一次的修改值都记录下来,再在$undo()$里回退每一个修改。说得是轻松,但是具体的实现还是要仔细安排一下顺序和细节的。

    其中$stk[top]$存修改的起止点;$last[]$存每次$extend()$前的$lst$值,用于路径回退上的$ch[x][c]$修改;$tag[]$表示点$i$这次操作新增点的数量,需要分为1,2讨论回退;$val[]$表示每次操作插入的字符$c$.

    有2个新增点的$undo()$稍微复杂一点,这里$stk[]={从lst回退的p';fa[q];再次回退的p'';q}$.

     1 #include<bits/stdc++.h>
     2 const int maxn = 200035;
     3 
     4 int n,top,stk[maxn<<2],last[maxn<<2],tag[maxn<<2],val[maxn<<2];
     5 long long ans;
     6 struct SAM
     7 {
     8     int ch[maxn][27],fa[maxn],len[maxn],lst,tot;
     9     void init()
    10     {
    11         lst = tot = 1;
    12     }
    13     void extend(int c)
    14     {
    15         int p = lst, np = ++tot;
    16         last[++last[0]] = lst;
    17         lst = np, len[np] = len[p]+1;
    18         val[tot] = c;
    19         for (; p&&!ch[p][c]; p=fa[p]) ch[p][c] = np;
    20         tag[tot] = 0, stk[++top] = p;
    21         if (!p) fa[np] = 1; 
    22         else{
    23             int q = ch[p][c];
    24             if (len[p]+1==len[q]) fa[np] = q;
    25             else{
    26                 int nq = ++tot;
    27                 len[nq] = len[p]+1;
    28                 tag[tot] = 2, val[tot] = c;
    29                 memcpy(ch[nq], ch[q], sizeof ch[q]);  
    30                 stk[++top] = fa[q];
    31                 fa[nq] = fa[q], fa[q] = fa[np] = nq;
    32                 for (; p&&ch[p][c]==q; p=fa[p]) ch[p][c] = nq;
    33                 stk[++top] = p, stk[++top] = q;
    34             }
    35         }
    36         ans += len[np]-len[fa[np]];
    37         if (!tag[tot]) tag[tot] = 1;
    38     }
    39     void undo()
    40     {
    41         if (tag[tot]==1){
    42             int p = last[last[0]--], fnd = stk[top--], c = val[tot];
    43             ans -= len[tot]-len[fa[tot]], lst = p;
    44             for (; p!=fnd; p=fa[p]) ch[p][c] = 0;
    45             memset(ch[tot], 0, sizeof ch[tot]), --tot;
    46         }else{
    47             int q = stk[top--], fnd2 = stk[top--], fatq = stk[top--], fnd1 = stk[top--];
    48             int p = last[last[0]--], c = val[tot];
    49             ans -= len[tot-1]-len[fa[tot-1]], lst = p;
    50             for (; p!=fnd1; p=fa[p]) ch[p][c] = 0;
    51             fa[q] = fatq;
    52             for (; p!=fnd2; p=fa[p]) ch[p][c] = q;
    53             memset(ch[tot], 0, sizeof ch[tot]), --tot;
    54             memset(ch[tot], 0, sizeof ch[tot]), --tot;
    55         }
    56     }
    57 }f;
    58 char s[maxn];
    59 
    60 int main()
    61 {
    62     f.init();
    63     scanf("%s",s+1);
    64     n = strlen(s+1);
    65     for (int i=1; i<=n; i++)
    66     {
    67         if (s[i]=='-') f.undo();
    68         else f.extend(s[i]-'a');
    69         printf("%lld
    ",ans);
    70     }
    71     return 0;
    72 }

    做法二:后缀平衡树

    具体的实现似乎可以用hash求LCP+multiset解决

    END

  • 相关阅读:
    OpenJudge 2764 数根 C++
    OpenJudge / Poj 1835 宇航员 C++
    elasticsearch系统性能调优总结
    ES基本查询总结
    Vim最全快捷键键位图
    Idea常用插件整合
    微信小程序开发资源汇总
    Java JNI调用本地动态库使用详解
    java开发调试定位分析工具大全
    Redux-saga使用教程详解
  • 原文地址:https://www.cnblogs.com/antiquality/p/10512652.html
Copyright © 2020-2023  润新知