集训讲字符串的时候我唯一想出正解的题……

链接

BZOJ 2865

题面

给出一个长度为n (n <= 5e5) 的字符串,对于每一位,求包含该位的、最短的、在原串中只出现过一次的子串。

题解

“只出现过一次”,想到后缀数组,后缀数组可以求出以第i位开头的最短的在原串中只出现过一次的子串——它的长度是min(height[rank[i]], height[rank[i] + 1) + 1。

所以我们枚举每个位置i,找到这个串,然后考虑它的贡献:

对于这个串之内的位置,答案可以用这个串的长度更新;

对于这个串右边的位置,串可以向右“延伸”直到包含该位置(延伸后的串显然也只出现过一次),所以答案可以用(该位置 - i + 1)来更新。

这两个分别用线段树维护即可。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define enter putchar('\n')
#define space putchar(' ')
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c > '9' || c < '0')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
} const int N = 500005, INF = 0x3f3f3f3f;
int n, sa[N], rnk[N], buf1[N], buf2[N], buc[N], height[N];
int data[2][4*N], lazy[2][4*N], pos[N];
char s[N]; void pushdown(int h, int k){
if(lazy[h][k] == INF) return;
lazy[h][k << 1] = min(lazy[h][k << 1], lazy[h][k]);
lazy[h][k << 1 | 1] = min(lazy[h][k << 1 | 1], lazy[h][k]);
data[h][k << 1] = min(data[h][k << 1], lazy[h][k]);
data[h][k << 1 | 1] = min(data[h][k << 1 | 1], lazy[h][k]);
lazy[h][k] = INF;
}
void modify(int h, int k, int l, int r, int ql, int qr, int x){
if(ql <= l && qr >= r){
data[h][k] = min(data[h][k], x);
lazy[h][k] = min(lazy[h][k], x);
return;
}
int mid = (l + r) >> 1;
if(ql <= mid) modify(h, k << 1, l, mid, ql, qr, x);
if(qr > mid) modify(h, k << 1 | 1, mid + 1, r, ql, qr, x);
data[h][k] = min(data[h][k << 1], data[h][k << 1 | 1]);
}
void pushdown_all(int k, int l, int r){
if(l == r) return (void)(pos[l] = k);
pushdown(0, k), pushdown(1, k);
int mid = (l + r) >> 1;
pushdown_all(k << 1, l, mid);
pushdown_all(k << 1 | 1, mid + 1, r);
}
void suffix_sort(){
int m = 128, *x = buf1, *y = buf2;
for(int i = 0; i <= m; i++) buc[i] = 0;
for(int i = 1; i <= n; i++) buc[x[i] = s[i]]++;
for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
for(int i = n; i; i--) sa[buc[x[i]]--] = i;
for(int k = 1, p = 0; k <= n && p < n; k *= 2, m = p, p = 0){
for(int i = n - k + 1; i <= n; i++) y[++p] = i;
for(int i = 1; i <= n; i++) if(sa[i] > k) y[++p] = sa[i] - k;
for(int i = 0; i <= m; i++) buc[i] = 0;
for(int i = 1; i <= n; i++) buc[x[y[i]]]++;
for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
for(int i = n; i; i--) sa[buc[x[y[i]]]--] = y[i];
swap(x, y), x[sa[1]] = 1, p = 1;
for(int i = 2; i <= n; i++)
x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p : ++p;
}
for(int i = 1; i <= n; i++) rnk[sa[i]] = i;
for(int i = 1, k = 0; i <= n; i++){
if(rnk[i] == 1) continue;
int j = sa[rnk[i] - 1];
if(k) k--;
while(i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++;
height[rnk[i]] = k;
}
} int main(){ scanf("%s", s + 1);
n = strlen(s + 1);
suffix_sort();
memset(data, INF, sizeof(data));
memset(lazy, INF, sizeof(lazy));
for(int i = 1; i <= n; i++){
int len = max(height[rnk[i]], height[rnk[i] + 1]);
if(i + len <= n) modify(0, 1, 1, n, i, i + len, len + 1);
if(i + len < n) modify(1, 1, 1, n, i + len + 1, n, 1 - i);
}
pushdown_all(1, 1, n);
for(int i = 1; i <= n; i++)
write(min(data[0][pos[i]], i + data[1][pos[i]])), enter; return 0;
}

BZOJ 2865 字符串识别 | 后缀数组 线段树的更多相关文章

  1. bzoj 2865 字符串识别 —— 后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865 唯一出现的子串就是每个后缀除去和别的后缀最长的 LCP 之外的前缀: 所以用这个更新一 ...

  2. bzoj 2865 字符串识别——后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865 做出 ht[ ] 之后,sa[ ] 上每个位置和它前面与后面取 LCP ,其中较大的长 ...

  3. 【BZOJ4556】[TJOI2016&HEOI2016] 字符串(后缀自动机+线段树合并+二分)

    点此看题面 大致题意: 给你一个字符串\(s\),每次问你一个子串\(s[a..b]\)的所有子串和\(s[c..d]\)的最长公共前缀. 二分 首先我们可以发现一个简单性质,即要求最长公共前缀,则我 ...

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

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

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

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

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

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

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

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

  8. BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)

    题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...

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

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

随机推荐

  1. zookeeper的原理及使用

    ZooKeeper是Hadoop Ecosystem中非常重要的组件,它的主要功能是为分布式系统提供一致性协调(Coordination)服务,与之对应的Google的类似服务叫Chubby.今天这篇 ...

  2. 2《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——操作文件

    已经学习了基本的命令,现在是时候学习操作文件了,这也是命令行的重要任务.还是基于本教程的事先规定,本教程是入门级的,不要求熟悉类似编辑文本的程序(这些文本编辑程序,将在下个系列教程中介绍, Learn ...

  3. cleanCode[1]:有意义的命名

    为什么要有意义的命名: 我们都曾经说过有朝一日再回头清理那些糟糕的代码,然而最终总是弃之不顾.稍后等于永不,我们需要立即行动,写优雅的代码. 写代码的过程中,读占的比例很大,所以首先要让代码易读. 有 ...

  4. 20155202 张旭《网络对抗》Exp2 后门原理与实践

    20155202 张旭<网络对抗>Exp2 后门原理与实践 基础问题回答 例举你能想到的一个后门进入到你系统中的可能方式? 捆绑在软件中 注入在可执行文件里 注入在office文件的宏里面 ...

  5. vue eslint报错解决办法

    若提示入下图时,在build / webpack.base.conf.js中, 找到 // const createLintingRule = () => ({// test: /\.(js|v ...

  6. [Zlib]_[初级]_[使用zlib库压缩和解压STL string]

    场景 1.一般在使用文本json传输数据, 数据量特别大时,传输的过程就特别耗时, 因为带宽或者socket的缓存是有限制的, 数据量越大, 传输时间就越长. 网站一般使用gzip来压缩成二进制. 说 ...

  7. vue-cli 3.0 实现A-Z字母滑动选择城市列表

    项目地址: https://github.com/caochangkui/vue-cli3 项目代码: 城市列表首页: City.vue <template> <div id=&qu ...

  8. PowerBI开发 第二篇:数据建模

    在分析数据时,不可能总是对单个数据表进行分析,有时需要把多个数据表导入到PowerBI中,通过多个表中的数据及其关系来执行一些复杂的数据分析任务,因此,为准确计算分析的结果,需要在数据建模中,创建数据 ...

  9. (2)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- .NetCore启动配置 和 .NetCoreWebApi

    什么是.Net Core?.Net Core是微软开发的另外一个可以跨Linux.Windows.mac等平台的.Net.Net Core相关知识看文章地步dotnet dllname.dll 运行P ...

  10. EditText点击出现光标但不弹出软键盘

    3.0以下版本可以用editText.setInputType(InputType.TYPE_NULL)来实现.或者设置editText.setKeyListener(null)来实现. 3.0以上版 ...