题意

给一个长度为\(n\)的字符串\(s\),再给定一个\(w\),问对于所有的\(i\in [1,n-w+1]\),\(s[i..i+w-1]\)有多少个不同字串。\(n,w\le 10^5\)。

分析

统计不同子串个数的问题可以使用后缀树。一个字符串的后缀树的总边长就是这个字符串的不同子串个数。解决这个问题,一个显然的方法就是划窗法,即每次删掉第一个字符,加入最后一个字符,再统计后缀树上边长的变更即可。

很明显这个方法需要一个在线的后缀树构建算法,可以用Ukkonen来做。那么我们如何求出每次删掉哪个后缀呢?我们删掉的肯定是当前后缀树中最长的后缀,也就是最早添加进去的那个叶子节点。所以我们维护一个队列,每次新建叶子的时候就加入队列中(压缩边也需要),每次删除队头即可。

代码

调了很久啊……这个题一定要想好再写(所有题都应该想好再写),会有一些需要注意的地方。好好利用删除的一定是叶子节点这个性质。

我的方法需要压缩边,即如果一个点只有一条出边,那么把这个点压缩掉。根据压缩后缀树的性质可以得到,每次最多删除一条边,压缩一条边。直接讨论一下now节点是否在这条边上就好啦。

然后,开long long……子串计数问题一定要注意这个啊!!

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long giant;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=2e5+10;
const int maxc=27;
giant ans=0,Ans[maxn];
int w,que[maxn],ql=1,qr=0;
struct ST {
const static int inf=1e8;
int t[maxn][maxc],father[maxn],sons[maxn],start[maxn],len[maxn],link[maxn],now,rem,s[maxn],n,leaf,tot,pool[maxn];
ST ():now(1),rem(0),n(0),leaf(0),tot(1) {
for (int i=1;i<maxn;++i) pool[i]=i;
father[1]=0;
len[0]=inf;
}
void erase(int &x) {
memset(t[x],0,sizeof t[x]),start[x]=len[x]=link[x]=father[x]=sons[x]=0;
pool[tot--]=x;
x=0;
}
int node(int star,int le) {
int nw=pool[++tot];
start[nw]=star,len[nw]=le,link[nw]=1;
return nw;
}
void add(int c) { // c is a char
s[++n]=c,++rem;
for (int last=1;rem;) {
while (rem>len[t[now][s[n-rem+1]]]) rem-=len[now=t[now][s[n-rem+1]]];
int ed=s[n-rem+1];
int &v=t[now][ed];
int x=s[start[v]+rem-1];
if (!v) {
father[que[++qr]=v=node(n-rem+1,inf)]=now;
++sons[now];
link[last]=now;
last=now;
} else if (x==c) {
link[last]=now;
last=now;
break;
} else {
int u=node(start[v],rem-1);
father[u]=father[v];
father[que[++qr]=t[u][c]=node(n,inf)]=u;
father[t[u][x]=v]=u,start[v]+=rem-1;
if (len[v]<inf) len[v]-=rem-1;
sons[link[last]=v=u]=2;
last=v;
}
++leaf;
if (now==1) --rem; else now=link[now];
}
}
void compress(int x) {
if (!father[x]) return;
if (sons[x] && (--sons[x])!=1) return;
int i;
for (i=1;i<maxc;++i) if (t[x][i]) break;
int u=t[x][i];
start[u]-=len[x];
if (len[u]<inf) len[u]+=len[x];
father[u]=father[x];
erase(t[father[x]][s[start[x]]]);
t[father[u]][s[start[u]]]=u;
}
void del(int x) { // x is a point
int f=father[x];
if (now==f) {
if (!rem || t[now][s[n-rem+1]]!=x) {
ans-=n-start[x]+1;
--leaf;
erase(t[f][s[start[x]]]);
if (now!=1) now=father[now],rem+=len[f];
compress(f);
return;
}
ans-=n-rem-start[x]+1;
start[x]=n-rem+1;
que[++qr]=x;
if (now==1) --rem; else now=link[now];
} else {
ans-=n-start[x]+1;
erase(t[f][s[start[x]]]);
compress(f);
--leaf;
}
}
void run() {
for (int i=1;i<=tot;++i) if (pool[i]!=1) ans+=min(len[pool[i]],n-start[pool[i]]+1);
}
} sut;
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("my.out","w",stdout);
#endif
int n,m;
static char s[maxn];
scanf("%s",s+1);
n=strlen(s+1);
m=read(),w=read();
for (int i=1;i<=w;++i)
sut.add(s[i]-'a'+1);
sut.run();
Ans[1]=ans;
for (int i=w+1;i<=n;++i) {
if (ql<=qr) sut.del(que[ql++]);
sut.add(s[i]-'a'+1);
ans+=sut.leaf;
Ans[i-w+1]=ans;
}
while (m--) printf("%lld\n",Ans[read()]);
return 0;
}

SWERC2015-I Text Processor的更多相关文章

  1. How To Use the AWK language to Manipulate Text in Linux

    https://www.digitalocean.com/community/tutorials/how-to-use-the-awk-language-to-manipulate-text-in-l ...

  2. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  3. windows进程详解

    1:系统必要进程system process    进程文件: [system process] or [system process]进程名称: Windows内存处理系统进程描述: Windows ...

  4. Guide to make CentOS 7 the perfect desktop

    原文地址:  http://www.dedoimedo.com/computers/fedora-pimp.html My original review of CentOS 7 was less e ...

  5. ti processor sdk linux am335x evm /bin/create-sdcard.sh hacking

    #!/bin/bash # # ti processor sdk linux am335x evm /bin/create-sdcard.sh hacking # 说明: # 本文主要对TI的sdk中 ...

  6. [r]Seven habits of effective text editing

    Seven habits of effective text editing(via) Bram Moolenaar November 2000 If you spend a lot of time ...

  7. AS 注解处理器 APT Processor MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  8. Separate code and data contexts: an architectural approach to virtual text sharing

    The present invention provides a processor including a core unit for processing requests from at lea ...

  9. Flexible implementation of a system management mode (SMM) in a processor

    A system management mode (SMM) of operating a processor includes only a basic set of hardwired hooks ...

随机推荐

  1. 20155306 2006-2007-2 《Java程序设计》第2周学习总结

    20155306 2006-2007-2 <Java程序设计>第2周学习总结 教材学习内容总结 第三章 基础语法: java中,基本类型:布尔(boolean):boolean类型分为tr ...

  2. 20145209 2016-2017-2 《Java程序设计》课程总结

    20145209 2016-2017-2 <Java程序设计>课程总结 每周作业链接汇总 预备作业01 http://www.cnblogs.com/liuyiyang/p/6194319 ...

  3. WPF 一个简单的颜色选择器

    原文:WPF 一个简单的颜色选择器 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/BYH371256/article/details/8340999 ...

  4. Mysql本地安装多实例后启动遇到的问题

    一.本文紧接上一篇[win10-MySql免安装版-安装/多实例] 在上一篇文章里,安装Mysql解压版后,复制多份到本地,实现了多实例的安装 在后续启动其它实例的时候会遇到一些问题,以下就是自己遇到 ...

  5. Yii2 模块module笔记

    包含内容: 使用GII新建module 建立子模块 在其他控制器中调用模块的操作(action) 1. 使用Gii工具新建module 注意模块的路径,我们没有写backend\modules\Art ...

  6. 那些不能遗忘的知识点回顾——C/C++系列(笔试面试高频题)

    有那么一些零碎的小知识点,偶尔很迷惑,偶尔被忽略,偶然却发现它们很重要,这段时间正好在温习这些,就整理在这里,一起学习一起提高!后面还会继续补充. ——前言 1.面向对象的特性 封装.继承.多态. 封 ...

  7. Flask 路由相关操作

    URL Route URL 后接 / 作为目录级访问 URL 后不接 / 作为文件级访问 from flask import Flask app = Flask(__name__) @app.rout ...

  8. 一个web应用的诞生(4)--数据存储

    上一章实现了登录的部分功能,之所以说是部分功能,是因为用户名和密码写成固定值肯定是不可以的,一个整体的功能,至少需要注册,登录,密码修改等,这就需要提供一个把这些值存储到数据库的能力. 当前的主流数据 ...

  9. nmap保存结果

    nmap 192.168.0.2 -oX D:\myscan.xml 参数解释: -oN <filespec> (标准输出) -oX <filespec> (XML输出) -o ...

  10. python爬虫之requests库

    在python爬虫中,要想获取url的原网页,就要用到众所周知的强大好用的requests库,在2018年python文档年度总结中,requests库使用率排行第一,接下来就开始简单的使用reque ...