zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    Android 节日短信送祝福(UI篇:3-选择短信与发送短信的Activity的实现)
    Android 节日短信送祝福(功能篇:2-短信历史记录Fragment的编写)
    Android 节日短信送祝福(功能篇:1-数据库操作类与自定义ContentProvider)
    Android AIDL 小结
    Android 异步更新UI-线程池-Future-Handler实例分析
    Android 利用线程运行栈StackTraceElement设计Android日志模块
    Android OkHttp网络连接封装工具类
    Android OKHttp源码解析
    Android开发人员不得不收集的代码(持续更新中)
    Android 为开发者准备的最佳 Android 函数库(2016 年版)
  • 原文地址:https://www.cnblogs.com/antiquality/p/10512652.html
Copyright © 2011-2022 走看看