P5108 仰望半月的夜空 SAM+线段树覆盖
$ \color{#0066ff}{ 题目描述 }$
半月的夜空中,寄托了多少人与人之间的思念啊
曦月知道,这些思念会汇集成一个字符串\(S(n = |S|)\)
由于思念汇集的过于复杂,因此曦月希望提炼出所有的思念
我们定义\(Y_S(i)\)表示对于字符串\(S\)而言,长度为\(i\)的子串中,字典序最小的,左端点最小的左端点的值
比如对于串\(S = "baa"\),\(Y_S(1) = 2, Y_S(2) = 2, Y_S(3) = 1\)
曦月会告知你\(S\)串,你只需要告诉曦月\(Y_S(i)(1 \le i \le n)\)即可
\(\color{#0066ff}{输入格式}\)
第一行,两个参数,分别是\(\sigma \in \{10, 26, 10^7\}\)和\(n\)
如果\(\sigma = 26\),那么第二行将是一个长为\(n\)的小写字母字符串\(S\)
其他情况下,第二行将输入\(n\)个位于\([0, \sigma]内\)的整数
\(\color{#0066ff}{输出格式}\)
输出一行,第iii个数表示\(Y_S(i)\)的值
\(\color{#0066ff}{输入样例}\)
26 11
remoonqaqac
26 11
txdydkwqaqa
10000000 17
9 9 8 2 4 4 3 5 3 1 9 2 6 0 8 1 7
\(\color{#0066ff}{输出样例}\)
8 10 8 8 2 2 2 2 2 2 1
9 9 9 5 5 5 5 3 3 1 1
14 14 14 14 10 10 10 10 4 4 4 4 4 4 3 2 1
\(\color{#0066ff}{数据范围与提示}\)
\(\color{#0066ff}{题解}\)
建立后缀自动机,要求左端点最小,你需要维护左端点,所以倒着插入,建立后缀树
这样树上的点代表的是某一后缀的前缀
后缀自动机上每个点维护一个pos为起始位置l
然后考虑后缀树上的一条边,它对应的字串长度就是$[父亲len+1,自己的len] $,那么对于这一区间的答案就可以用自己子树的pos最小值来更新
至于字典序最小?,我们可以dfs出后缀树中每个节点是它父亲的那个儿子,然后考虑倒着覆盖,当前字典序是最优的,把原来的覆盖掉,用线段树维护答案就行了
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 3e5 + 10;
const int inf = 0x7fffffff;
struct Tree {
protected:
struct node {
node *ch[2];
int l, r, val, tag;
node(int l = 0, int r = 0, int val = 0, int tag = -1): l(l), r(r), val(val), tag(tag) {
ch[0] = ch[1] = NULL;
}
void trn(int v) { val = tag = v; }
void dwn() {
if(tag == -1) return;
ch[0]->trn(tag);
ch[1]->trn(tag);
tag = -1;
}
int mid() { return (l + r) >> 1; }
}*root;
void build(node *&o, int l, int r) {
o = new node(l, r);
if(l == r) return;
build(o->ch[0], l, o->mid());
build(o->ch[1], o->mid() + 1, r);
}
void lazy(node *o, int l, int r, int val) {
if(l > r) return;
if(l <= o->l && o->r <= r) return o->trn(val);
o->dwn();
if(l <= o->mid()) lazy(o->ch[0], l, r, val);
if(r > o->mid()) lazy(o->ch[1], l, r, val);
}
void out(node *o) {
if(o->l == o->r) return (void)(printf("%d ", o->val));
o->dwn();
out(o->ch[0]); out(o->ch[1]);
}
public:
void build(int n) { build(root, 1, n); }
void lazy(int l, int r, int val) { lazy(root, l, r, val); }
void out() { out(root); }
}tree;
struct SAM {
protected:
struct node {
std::map<int, node*> ch, treech;
node *fa;
int len, pos;
node(int len = 0, int pos = 0): len(len), pos(pos) {
fa = NULL;
ch.clear(), treech.clear();
}
}pool[maxn << 1], *tail, *root, *lst;
int s[maxn];
char ls[maxn];
void extend(int c, int id) {
node *o = new(tail++) node(lst->len + 1, id), *v = lst;
for(; v && !v->ch[c]; v = v->fa) v->ch[c] = o;
if(!v) o->fa = root;
else if(v->len + 1 == v->ch[c]->len) o->fa = v->ch[c];
else {
node *n = new(tail++) node(v->len + 1, v->ch[c]->pos), *d = v->ch[c];
n->ch = d->ch, n->fa = d->fa, d->fa = o->fa = n;
for(; v && v->ch[c] == d; v = v->fa) v->ch[c] = n;
}
lst = o;
}
void getmin(node *o) {
for(std::pair<int, node*> i : o->treech) {
getmin(i.second);
o->pos = std::min(o->pos, i.second->pos);
}
}
void getans(node *o) {
tree.lazy((o->fa? o->fa->len + 1 : 1), o->len, o->pos);
for(std::map<int, node*>::reverse_iterator it = o->treech.rbegin(); it != o->treech.rend(); it++)
getans(it->second);
}
public:
SAM() {
tail = pool;
root = lst = new(tail++) node();
}
void init(int bel, int len) {
if(bel == 26) {
scanf("%s", ls + 1);
for(int i = 1; i <= len; i++) s[i] = ls[i] - 'a';
}
else {
for(int i = 1; i <= len; i++) s[i] = in();
}
for(int i = len; i >= 1; i--) extend(s[i], i);
}
void build() {
for(node *o = pool + 1; o != tail; o++)
o->fa->treech[s[o->pos + o->fa->len]] = o;
}
void getmin() { getmin(root); }
void getans() { getans(root); }
}s;
int main() {
int val = in(), n = in();
s.init(val, n);
tree.build(n);
s.build();
s.getmin();
s.getans();
tree.out();
return 0;
}
P5108 仰望半月的夜空 SAM+线段树覆盖的更多相关文章
- 洛谷 P5108 仰望半月的夜空 解题报告
P5108 仰望半月的夜空 题目描述 半月的夜空中,寄托了多少人与人之间的思念啊 曦月知道,这些思念会汇集成一个字符串\(S(n = |S|)\) 由于思念汇集的过于复杂,因此曦月希望提炼出所有的思念 ...
- bzoj1396识别子串(SAM+线段树)
复习SAM板子啦!考前刷水有益身心健康当然这不是板子题/水题…… 很容易发现只在i位置出现的串一定是个前缀串.那么对答案的贡献分成两部分:一部分是len[x]-fa~len[x]的这部分贡献会是r-l ...
- 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree
原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...
- UOJ#395. 【NOI2018】你的名字 字符串,SAM,线段树合并
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ395.html 题解 记得同步赛的时候这题我爆0了,最暴力的暴力都没调出来. 首先我们看看 68 分怎么做 ...
- Codeforces 700E. Cool Slogans 字符串,SAM,线段树合并,动态规划
原文链接https://www.cnblogs.com/zhouzhendong/p/CF700E.html 题解 首先建个SAM. 一个结论:对于parent树上任意一个点x,以及它所代表的子树内任 ...
- BZOJ1396 识别子串 字符串 SAM 线段树
原文链接http://www.cnblogs.com/zhouzhendong/p/9004467.html 题目传送门 - BZOJ1396 题意 给定一个字符串$s$,$|s|\leq 10^5$ ...
- loj#2059. 「TJOI / HEOI2016」字符串 sam+线段树合并+倍增
题意:给你一个子串,m次询问,每次给你abcd,问你子串sa-b的所有子串和子串sc-d的最长公共前缀是多长 题解:首先要求两个子串的最长公共前缀就是把反过来插入变成最长公共后缀,两个节点在paren ...
- 2019.02.28 bzoj4199: [Noi2015]品酒大会(sam+线段树)
传送门 题意:给一个串,每个位置有一个权值,当S[s...s+len−1]=S[t...t+len−1]&&S[s...s+len]̸=S[t..t+len]S[s...s+len-1 ...
- 2019.02.27 bzoj4556: [Tjoi2016&Heoi2016]字符串(二分答案+sam+线段树合并)
传送门 题意:给一个字符串SSS. 有mmm次询问,每次给四个参数a,b,c,da,b,c,da,b,c,d,问s[a...b]s[a...b]s[a...b]的所有子串和s[x...y]s[x... ...
随机推荐
- C++ split
/*************************************************Function: splitDescription: 根据空格切分字符串Calls: // 被本函 ...
- 制作initramfs/initrd镜像
Linux kernel在自身初始化完成之后,需要能够找到并运行第一个用户程序(这个程序通常叫做"init"程序).用户程序存在于文件系统之中,因此,内核必须找到并挂载一个文件系统 ...
- 线上应用故障排查:高CPU占用
转自:hankchen,http://www.blogjava.net/hankchen 一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环. 以我们最近出现的一个实际故障 ...
- Openssl smime命令
一.简介 S/MIME工具,用于处理S/MIME邮件,它能加密.解密.签名和验证S/MIME消息 二.语法 openssl smime [-encrypt] [-decrypt] [-sign] [- ...
- SetDns.bat 2014-03-28 20:00:19
此BAT文件,可以帮助便捷切换dns设置,Win7系统需使用管理员身份运行. @echo off echo 设置为GoogleDNS(1)/dhcp(2)/OpenDNS(3) set /p sel= ...
- windows server2012安装mysql时一直停留在start server的解决方法
安装的时候,starting server 卡住 原因分析 这个问题小编安装mysql时也碰到过,出现这个问题是my.ini文件没有复制成功了,我们只要在mysql安装目录把把目录中的备份的my-sm ...
- Eclipse快捷键和练习题(倒叙,排序)
1 快捷键 内容辅助键 Alt+/ 自动补齐main方法 main 然后 Alt+/ 自动补齐输出语句 syso 然后 Alt+/ 格式化Ctrl+Shift+f 代码区域右键 -- So ...
- Understanding sun.misc.Unsafe
转自: https://dzone.com/articles/understanding-sunmiscunsafe The biggest competitor to the Java virtua ...
- JS 前端构建工具gulpjs的使用介绍及技巧
gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学习起来很容易,而且gulpjs使用的是nodejs中stream来读取和操作数据,其速 ...
- Java对称加密算法
对称加密算法概念 加密密钥和解密密钥相同,大部分算法加密揭秘过程互逆. 特点:算法公开.(相比非对称加密)计算量小.加密速度快.效率高. 弱点:双方都使用同样的密钥,安全性得不到保证. 常用对称加密算 ...