bzoj1396: 识别子串
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define maxn 100005
#define inf 100000000
using namespace std;
char st[maxn];
int n,tot,last,root,sum[maxn<<],tmp[maxn<<],fa[maxn<<],son[maxn<<][],dist[maxn<<],ri[maxn<<],pos[maxn<<];
struct Tsegment{
void prepare(){tot=last=root=,memset(ri,,sizeof(ri));}
int newnode(int x){
dist[++tot]=x; return tot;
}
void add(int op,int x){
int p=last,np=newnode(dist[p]+); last=np; ri[np]=; pos[np]=op;
for (;p&&!son[p][x];p=fa[p]) son[p][x]=np;
if (p==) fa[np]=root;
else{
int q=son[p][x];
if (dist[p]+==dist[q]) fa[np]=q;
else{
int nq=newnode(dist[p]+);
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for (;p&&son[p][x]==q;p=fa[p]) son[p][x]=nq;
}
}
}
}SAM;
struct Fsegment{
int l,r,lazy,val;
}tree1[maxn*];
struct date{
void build(int k,int l,int r){
tree1[k].lazy=tree1[k].val=inf; tree1[k].l=l,tree1[k].r=r;
if (l==r) return;
int mid=(l+r)/;
build(k*,l,mid),build(k*+,mid+,r);
}
void change(int k,int l,int r,int x,int y,int z){
if (x>y) return;
if (tree1[k].lazy!=inf){
if (tree1[k*].l) pushdown(k*,tree1[k].lazy);
if (tree1[k*+].l) pushdown(k*+,tree1[k].lazy);
tree1[k].lazy=inf;
}
if (l>=x&&r<=y){
pushdown(k,z);
return;
} int mid=(l+r)/;
if (x<=mid) change(k*,l,mid,x,y,z);
if (y>mid) change(k*+,mid+,r,x,y,z);
}
void pushdown(int k,int x){
tree1[k].lazy=min(tree1[k].lazy,x);
if (tree1[k].l==tree1[k].r) tree1[k].val=min(tree1[k].val,tree1[k].lazy);
}
int query(int k,int l,int r,int x){
if (tree1[k].lazy!=inf){
if (tree1[k*].l) pushdown(k*,tree1[k].lazy);
if (tree1[k*+].l) pushdown(k*+,tree1[k].lazy);
tree1[k].lazy=inf;
}
if (l==r&&r==x) return tree1[k].val;
int mid=(l+r)>>,ans=inf;
if (x<=mid) ans=min(ans,query(k*,l,mid,x));
else ans=min(ans,query(k*+,mid+,r,x));
return ans;
}
}Tree1;
struct Ksegment{
int l,r,val,lazy;
}tree[maxn*];
struct Graph{
void build(int k,int l,int r){
tree[k].l=l,tree[k].r=r,tree[k].lazy=tree[k].val=inf;
if (l==r) return; int mid=(l+r)/;
build(k*,l,mid),build(k*+,mid+,r);
}
void change(int k,int l,int r,int x,int y,int z){
if (x>y) return;
if (tree[k].lazy!=inf){
if (tree[k*].l) pushdown(k*,tree[k].lazy);
if (tree[k*+].l) pushdown(k*+,tree[k].lazy);
tree[k].lazy=inf;
}
if (l>=x&&r<=y){
pushdown(k,z);
return;
} int mid=(l+r)>>;
if (x<=mid) change(k*,l,mid,x,y,z);
if (y>mid) change(k*+,mid+,r,x,y,z);
}
void pushdown(int k,int x){
tree[k].lazy=min(tree[k].lazy,x);
if (tree[k].l==tree[k].r) tree[k].val=min(tree[k].val,tree[k].lazy);
}
int query(int k,int l,int r,int x){
if (tree[k].lazy!=inf){
if (tree[k*].l) pushdown(k*,tree[k].lazy);
if (tree[k*+].r) pushdown(k*+,tree[k].lazy);
tree[k].lazy=inf;
}
if (l==r&&r==x) return tree[k].val;
int mid=(l+r)>>,ans=inf;
if (x<=mid) ans=min(ans,query(k*,l,mid,x));
else ans=min(ans,query(k*+,mid+,r,x));
return ans;
}
}Tree;
int main(){
scanf("%s",st+),n=strlen(st+);
SAM.prepare();
for (int i=;i<=n;i++) SAM.add(i,st[i]-'a');
memset(sum,,sizeof(sum));
for (int i=;i<=tot;i++) sum[dist[i]]++;
for (int i=;i<=tot;i++) sum[i]+=sum[i-];
for (int i=;i<=tot;i++) tmp[sum[dist[i]]--]=i;
for (int i=tot,x;i>=;i--){
x=tmp[i];
if (fa[x]) ri[fa[x]]+=ri[x];
}
ri[root]=;
Tree1.build(,,n);
Tree.build(,,n);
for (int i=;i<=tot;i++){
if (ri[i]!=) continue;
int x=pos[i],y=dist[i],z=dist[fa[i]]+;
Tree1.change(,,n,x-y+,x-z+,x); //第一棵线段树按位置,记得减
Tree.change(,,n,x-z+,x,z); //第二棵线段树按长度
}
for (int i=;i<=n;i++){
printf("%d\n",min(Tree1.query(,,n,i)-i+,Tree.query(,,n,i)));
}
return ;
}
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1396
题目大意:
做法;看到题目中所说的T在S中只出现过一次,就很容易想到用后缀自动机嘛,显然就是right值为一的状态,而且right值为一的状态只能是每次add时第一个新建的点,这很显然嘛,这就很方便记录了。然后再用线段树维护一下最小值,稍微想一下就行,当时我竟然是很快就想到了,不过我inf开小了,狂WA不止。
后缀自动机+线段树。
bzoj1396: 识别子串的更多相关文章
- BZOJ1396 识别子串【SAM+SegmentTree】
BZOJ1396 识别子串 给定一个串\(s\),对于串中的每个位置,输出经过这个位置且只在\(s\)中出现一次的子串的最短长度 朴素的想法是,我们要找到那些只出现一次的子串,之后遍历每个串,把串所覆 ...
- bzoj千题计划318:bzoj1396: 识别子串(后缀自动机 + 线段树)
https://www.lydsy.com/JudgeOnline/problem.php?id=1396 后缀自动机的parent树上,如果不是叶子节点,那么至少有两个子节点 而一个状态所代表子串的 ...
- BZOJ1396:识别子串(SAM)
Description Input 一行,一个由小写字母组成的字符串S,长度不超过10^5 Output L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长. Sample I ...
- BZOJ-1396: 识别子串
后缀自动机+线段树 先建出\(sam\),统计一遍每个点的\(right\)集合大小\(siz\),对于\(siz=1\)的点\(x\),他所代表的子串只会出现一次,设\(y=fa[x]\),则这个点 ...
- BZOJ1396: 识别子串(后缀自动机,线段树)
Description Input 一行,一个由小写字母组成的字符串S,长度不超过10^5 Output L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长. Sample I ...
- BZOJ1396 识别子串 和 BZOJ2865 字符串识别
字符串识别 2865: 字符串识别 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 839 Solved: 261[Submit][Status][D ...
- BZOJ1396 识别子串 字符串 SAM 线段树
原文链接http://www.cnblogs.com/zhouzhendong/p/9004467.html 题目传送门 - BZOJ1396 题意 给定一个字符串$s$,$|s|\leq 10^5$ ...
- BZOJ bzoj1396 识别子串
题面: bzoj1396 题解: 先建出SAM,并计算right集合大小.显然符合条件的点的right集合大小为1. 对于每个right集合为1的状态显然可以算出这些状态的pos以及maxlen和mi ...
- BZOJ1396: 识别子串(后缀自动机 线段树)
题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...
随机推荐
- IE8 HACK介绍
1.‘\9’: eg:.test { color/*\**/: blue\9 }.header {width:300px;} /* 所有浏览器*/.header {width/*\**/:330px\ ...
- 批量去除Teleport Pro整站下载文件冗余代码
teleport pro tppabs标签批量删除 teleport pro tppabs标签批量删除 使 用Teleport Pro下载的网页代码中包含了很多垃圾代码,比如下载的html网页代码中会 ...
- IE6/IE7/IE8/Firefox/Chrome/Safari的CSS hack兼容一览表
浏览器兼容问题一直是前段开发工程师比较头痛的问题,熟悉了里面的规则也就变得简单了,这里有一份资料可以分享给大家,大家平时开发过程中遵循这个规律的话,会变得轻松多了: 各浏览器CSS hack兼容表: ...
- WPF Adorner+附加属性 实现控件友好提示
标题太空泛,直接上图 无论是在验证啊,还是提示方面等一些右上角的角标之类的效果,我们会怎么做? 这里介绍一种稍微简单一些的方法,利用附加属性和Adorner来完成. 例如WPF自带的控件上要加这样的效 ...
- 海王星给你好看!FineUI v4.0公测版发布暨《你找BUG我送书》活动开始(活动已结束!)
<FineUI v4.0 你找BUG我送书>活动已结束,恭喜如下三位网友获得由 FineUI 作者亲自翻译的图书<jQuery实战 第二版>! 奋斗~ 吉吉﹑ purplebo ...
- 从零开始打造个人专属命令行工具集——yargs完全指南
前言 使用命令行程序对程序员来说很常见,就算是前端工程师或者开发gui的,也需要使用命令行来编译程序或者打包程序 熟练使用命令行工具能极大的提高开发效率,linux自带的命令行工具都非常的有用,但是这 ...
- OFFSET约束(OFFSET IN 和OFFSET OUT)
OFFSET 的意思是偏移.对于同步时序电路来说,数据和时钟之间的偏移量是必须要关注的.OFFSET IN和OUT分别对应的是输入和输出FPGA数据和时钟之间的偏移关系,本文将分析这一种关系.阅读本文 ...
- C# 7.0 新特性1: 基于Tuple的“多”返回值方法
本文基于Roslyn项目中的Issue:#347 展开讨论. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: ...
- 青瓷引擎之纯JavaScript打造HTML5游戏第二弹——《跳跃的方块》Part 10(排行榜界面&界面管理)
继上一次介绍了<神奇的六边形>的完整游戏开发流程后(可点击这里查看),这次将为大家介绍另外一款魔性游戏<跳跃的方块>的完整开发流程. (点击图片可进入游戏体验) 因内容太多,为 ...
- 硬件升级win8.1重新安装系统
上次重装系统一年后升级了硬件配置,双11后,再次折腾系统. 配置硬件的选择 部分配件已经升级过了,之前的一直是AMD平台,发热大功耗高,08年我配的AMD 8450+映泰GX790 128M待机在10 ...