Description

XX在进行字符串研究的时候,遇到了一个十分棘手的问题。

在这个问题中,给定一个字符串S,与一个整数K,定义S的子串T=S(i, j)是关于第K位的识别子串,满足以下两个条件:

1、i≤K≤j。

2、子串T只在S中出现过一次。

例如,S="banana",K=5,则关于第K位的识别子串有"nana","anan","anana","nan","banan"和"banana"。

现在,给定S,XX希望知道对于S的每一位,最短的识别子串长度是多少,请你来帮助他。

Input

仅一行,输入长度为N的字符串S。

Output

输出N行,每行一个整数,第i行的整数表示对于第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

N<=5*10^5


首先发现可以按照每个后缀统计贡献

然后直接把每个后缀和前后排名的串lcp的max:len求出来,这些值是不能更新的

然后对于$[i,i+len] \(用len+1更新,对于\)[i+len,n]$用一个等差数列更新min

等差数列维护直接标记永久化就可以了

然后注意特判是不是没有合法的解


#include<bits/stdc++.h>

using namespace std;

typedef pair<int, int> pi;
const int N = 5e5 + 10;
const int INF_of_int = 1e9; int typ1[N << 2], typ2[N << 2]; #define LD (t << 1)
#define RD (t << 1 | 1) void build(int t, int l, int r) {
typ1[t] = INF_of_int;
typ2[t] = -INF_of_int;
if (l == r) return;
int mid = (l + r) >> 1;
build(LD, l, mid);
build(RD, mid + 1, r);
} void modify(int t, int l, int r, int ql, int qr, int typ, int val) {
if (ql > qr) return;
if (ql <= l && r <= qr) {
if (typ == 1) {
typ1[t] = min(typ1[t], val);
} else {
typ2[t] = max(typ2[t], val);
}
return;
}
int mid = (l + r) >> 1;
if (qr <= mid) modify(LD, l, mid, ql, qr, typ, val);
else if (ql > mid) modify(RD, mid + 1, r, ql, qr, typ, val);
else {
modify(LD, l, mid, ql, mid, typ, val);
modify(RD, mid + 1, r, mid + 1, qr, typ, val);
}
} void output(int t, int l, int r, int val, int pos) {
if (typ1[t]) val = min(val, typ1[t]);
if (typ2[t]) val = min(val, pos - typ2[t] + 1);
if (l == r) {
printf("%d\n", val);
return;
}
int mid = (l + r) >> 1;
if (pos <= mid) output(LD, l, mid, val, pos);
else output(RD, mid + 1, r, val, pos);
} struct Suffix_Array {
int s[N], n, m;
int c[N], x[N], y[N];
int sa[N], rank[N], height[N]; void init(int len, char *c) {
n = len, m = 0;
for (int i = 1; i <= n; i++) {
s[i] = c[i];
m = max(m, s[i]);
}
} void radix_sort() {
for (int i = 1; i <= m; i++) c[i] = 0;
for (int i = 1; i <= n; i++) c[x[y[i]]]++;
for (int i = 1; i <= m; i++) c[i] += c[i - 1];
for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i];
} void buildsa() {
for (int i = 1; i <= n; i++) x[i] = s[i], y[i] = i;
radix_sort();
int now;
for (int k = 1; k <= n; k <<= 1) {
now = 0;
for (int i = n - k + 1; i <= n; i++) y[++now] = i;
for (int i = 1; i <= n; i++) if (sa[i] > k) y[++now] = sa[i] - k;
radix_sort();
y[sa[1]] = now = 1;
for (int i = 2; i <= n; i++) y[sa[i]] = (x[sa[i]] == x[sa[i - 1]] && x[sa[i] + k] == x[sa[i - 1] + k]) ? now : ++now;
swap(x, y);
if (now == n) break;
m = now;
}
} void buildrank() {
for (int i = 1; i <= n; i++) rank[sa[i]] = i;
} void buildheight() {
for (int i = 1; i <= n; i++) {
int k = max(height[rank[i - 1]] - 1, 0);
for (; s[i + k] == s[sa[rank[i] - 1] + k]; k++);
height[rank[i]] = k;
}
} void build(int len, char *c) {
init(len, c);
buildsa();
buildrank();
buildheight();
} void solve() {
for (int i = 1; i <= n; i++) {
int len = max(height[rank[i]], height[rank[i] + 1]);
if (i + len > n) continue;
modify(1, 1, n, i, i + len, 1, len + 1);
modify(1, 1, n, i + len, n, 2, i);
}
}
} Sa; int len;
char s[N]; int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
scanf("%s", s + 1);
len = strlen(s + 1);
Sa.build(len, s);
build(1, 1, len);
Sa.solve();
for (int i = 1; i <= len; i++) output(1, 1, len, len, i);
return 0;
}

BZOJ1369/BZOJ2865 【后缀数组+线段树】的更多相关文章

  1. BZOJ 1396: 识别子串( 后缀数组 + 线段树 )

    这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...

  2. 【XSY1551】往事 广义后缀数组 线段树合并

    题目大意 给你一颗trie树,令\(s_i\)为点\(i\)到根的路径上的字符组成的字符串.求\(max_{u\neq v}(LCP(s_u,s_v)+LCS(s_u,s_v))\) \(LCP=\) ...

  3. Luogu4770 NOI2018你的名字(后缀数组+线段树)

    即求b串有多少个本质不同的非空子串,在a串的给定区间内未出现.即使已经8102年并且马上就9102年了,还是要高举SA伟大旗帜不动摇. 考虑离线,将所有询问串及一开始给的串加分隔符连起来,求出SA.对 ...

  4. BZOJ 2865 字符串识别 | 后缀数组 线段树

    集训讲字符串的时候我唯一想出正解的题-- 链接 BZOJ 2865 题面 给出一个长度为n (n <= 5e5) 的字符串,对于每一位,求包含该位的.最短的.在原串中只出现过一次的子串. 题解 ...

  5. bzoj 1396: 识别子串 && bzoj 2865: 字符串识别【后缀数组+线段树】

    根据height数组的定义,和当前后缀串i最长的相同串的长度就是max(height[i],height[i+1]),这个后缀贡献的最短不同串长度就是len=max(height[i],height[ ...

  6. Codeforces 1063F - String Journey(后缀数组+线段树+dp)

    Codeforces 题面传送门 & 洛谷题面传送门 神仙题,做了我整整 2.5h,写篇题解纪念下逝去的中午 后排膜拜 1 年前就独立切掉此题的 ymx,我在 2021 年的第 5270 个小 ...

  7. [CF1063F]String Journey[后缀数组+线段树]

    题意 在 \(S\) 中找出 \(t\) 个子串满足 \(t_{i+1}\) 是 \(t_{i}\) 的子串,要让 \(t\) 最大. \(|S| \leq 5\times 10^5\). 分析 定义 ...

  8. BZOJ 2865 字符串识别(后缀数组+线段树)

    很容易想到只考虑后缀长度必须为\(max(height[rk[i]],height[rk[i]+1])+1\)(即\([i,i+x-1]\)代表的串只出现过一次)然后我正着做一遍反着做一遍,再取一个\ ...

  9. [CF653F] Paper task - 后缀数组,线段树,vector

    [CF653F] Paper task Description 给定一个括号序列,统计合法的本质不同子串的个数. Solution 很容易想到,只要在传统统计本质不同子串的基础上修改一下即可. 考虑经 ...

  10. BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)

    题目链接 SAM:能成为识别子串的只有那些|right|=1的节点代表的串. 设这个节点对应原串的右端点为r[i],则如果|right[i]|=1,即\(s[\ [r_i-len_i+1,r_i-le ...

随机推荐

  1. C语言位域解析&符号位扩展规则

    从一个例子说起: int main(void){ union{ int i; struct{ ; ; ; }bits; }num; printf("Input an integer for ...

  2. CAS-自旋锁

    自旋锁 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环.  获取锁的线程一直处于 ...

  3. dd 命令常用功能收集(ing...)

    xu言: 发现自己老是忘记一些不怎么常用,但是一定会用到的命令...so,做个备忘吧 Tips: sudo sh -c "head -c 15M /dev/urandom > test ...

  4. Java compiler level does not match the version of the installed Java project facet.解决方法

    右键项目“Properties”,在弹出的“Properties”窗口左侧,单击“Project Facets”,打开“Project Facets”页面. 在页面中的“Java”下拉列表中,选择相应 ...

  5. IDEA搭建ssm框架测试衍生出的问题The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: D:\Develop\jdk7\jdk1.7.0_79\bin;

    最近玩起IDEA这开发工具,搭建ssm框架测试时,部署项目出现如下问题: 信息: The APR based Apache Tomcat Native library which allows opt ...

  6. 安全模式下卸载windows installer打包的软件(转)

    安全模式下卸载windows installer打包的软件 起因: 主机系统MAC,虚拟软件Parallels Desktop, 虚拟系统 Win 7. 今天在虚拟机WIN7里面安装了某个软件导致重启 ...

  7. IDEA秒退或者一直让填写激活码问题

    IDEA秒退或者一直让填写激活码 1)复制  0.0.0.0 account.jetbrains.com 2)找到你本地的这个路径,我的电脑是windows,所以路径为: 3)点击hosts,添加刚刚 ...

  8. spark RDD操作的底层实现原理

    RDD操作闭包外部变量原则 RDD相关操作都需要传入自定义闭包函数(closure),如果这个函数需要访问外部变量,那么需要遵循一定的规则,否则会抛出运行时异常.闭包函数传入到节点时,需要经过下面的步 ...

  9. Mybatis学习总结--------Mybatis <where>标签 (九)

      <select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WH ...

  10. Error: Chunk.entry was removed. Use hasRuntime()错误解决

      Error: Chunk.entry was removed. Use hasRuntime()错误解决           执行如下命令 npm uninstall --save-dev ext ...