又是一道\(SAM\)维护\(endpos\)集合的题,我直接把CF700E的板子粘过来了QwQ

思路

如果我们有\([l,r]\)对应的\(SAM\),只需要在上面贪心就可以了。因为要求的是字典序比\(T\)大且最小的子串,我们从前到后让尽可能多的位相等,如果再也无法相等了就从后往前找一位变大。

但是每次询问会给我们一个可行区间\([l,r]\),而我们又显然不能直接把对应区间的\(SAM\)建出来,否则复杂度会\(GG\)。

仔细想一下,其实我们并不需要知道\([l,r]\)区间对应的\(SAM\),只要知道能否向某一个结点转移就行了。这个我们可以用\(endpos\)集合来判断。具体一下,就是当前已经考虑了\(i\)个字符且在结点\(u\),现在需要判断能否转移到\(v\),只需要判断\(u\)是否有到\(v\)的转移边和\(v\)结点的\(endpos\)是否有元素在\([l+i-1,r]\)中就行了

\(endpos\)拿线段树合并维护一下就行了(也可以用树上主席树搞一下)

其实本菜鸡来学这个套路完全是为写你的名字做铺垫的

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <queue>
#include <map>
#include <set> using namespace std; #define IINF 0x3f3f3f3f3f3f3f3fLL
#define ull unsigned long long
#define pii pair<int, int>
#define uint unsigned int
#define mii map<int, int>
#define lbd lower_bound
#define ubd upper_bound
#define INF 0x3f3f3f3f
#define vi vector<int>
#define ll long long
#define mp make_pair
#define pb push_back #define N 200000
#define Q 200000 int n, q, m;
char s[N+5], t[N+5], ans[N+5]; struct SAM {
int nxt[26][2*N+5], maxlen[2*N+5], link[2*N+5], tot, lst;
int sumv[100*N+5], ch[2][100*N+5], root[2*N+5], nid;
int node[N+5];
vi G[2*N+5];
void init() {
tot = lst = 1;
nid = 0;
}
void pushup(int o) {
sumv[o] = sumv[ch[0][o]]+sumv[ch[1][o]];
}
void add(int &o, int l, int r, int x) {
if(!o) o = ++nid;
if(l == r) {
sumv[o] = 1;
return ;
}
int mid = (l+r)>>1;
if(x <= mid) add(ch[0][o], l, mid, x);
else add(ch[1][o], mid+1, r, x);
pushup(o);
}
int merge(int o, int u, int l, int r) {
if(!o || !u) return o|u;
int v = ++nid;
if(l == r) {
sumv[v] = sumv[o]+sumv[u] ? 1 : 0;
return v;
}
int mid = (l+r)>>1;
ch[0][v] = merge(ch[0][o], ch[0][u], l, mid);
ch[1][v] = merge(ch[1][o], ch[1][u], mid+1, r);
pushup(v);
return v;
}
int query(int o, int l, int r, int L, int R) {
if(L > R || !o) return 0;
if(L <= l && r <= R) return sumv[o];
int ret = 0, mid = (l+r)>>1;
if(L <= mid) ret += query(ch[0][o], l, mid, L, R);
if(R > mid) ret += query(ch[1][o], mid+1, r, L, R);
return ret;
}
void extend(int c) {
int cur = ++tot;
maxlen[cur] = maxlen[lst]+1;
while(lst && !nxt[c][lst]) nxt[c][lst] = cur, lst = link[lst];
if(!lst) link[cur] = 1;
else {
int p = lst, q = nxt[c][p];
if(maxlen[q] == maxlen[p]+1) link[cur] = q;
else {
int clone = ++tot;
maxlen[clone] = maxlen[p]+1;
link[clone] = link[q], link[q] = link[cur] = clone;
for(int i = 0; i < 26; ++i) nxt[i][clone] = nxt[i][q];
while(p && nxt[c][p] == q) nxt[c][p] = clone, p = link[p];
}
}
lst = cur;
}
void dfs(int u) {
for(int i = 0, v; i < G[u].size(); ++i) {
v = G[u][i];
dfs(v);
root[u] = merge(root[u], root[v], 1, n);
}
}
void build() {
init();
for(int i = 1; i <= n; ++i) {
add(root[tot+1], 1, n, i);
extend(s[i]-'a');
}
for(int i = 2; i <= tot; ++i) G[link[i]].pb(i);
dfs(1);
}
void search(int L, int R) {
m = strlen(t+1);
int u = 1, v, x;
for(int i = 1; 1; ++i) {
ans[i] = -1;
for(int j = max(t[i]-'a'+1, 0); j < 26; ++j) {
v = nxt[j][u];
if(v && query(root[v], 1, n, L+i-1, R)) {
ans[i] = j;
break;
}
}
v = nxt[max(t[i]-'a', 0)][u];
x = i;
if(i == m+1 || !v || !query(root[v], 1, n, L+i-1, R)) break;
u = v;
}
while(x && ans[x] == -1) --x;
if(!x) printf("-1\n");
else {
for(int j = 1; j < x; ++j) printf("%c", t[j]);
printf("%c\n", ans[x]+'a');
}
}
}sam; int main() {
scanf("%s%d", s+1, &q);
n = strlen(s+1);
sam.build();
for(int i = 1, L, R; i <= q; ++i) {
scanf("%d%d%s", &L, &R, t+1);
sam.search(L, R);
}
return 0;
}

CF1037H Security——SAM+线段树合并的更多相关文章

  1. 【Codeforces 1037H】Security(SAM & 线段树合并)

    Description 给出一个字符串 \(S\). 给出 \(Q\) 个操作,给出 \(L, R, T\),求字典序最小的 \(S_1\),使得 \(S^\prime\) 为\(S[L..R]\) ...

  2. CodeForces - 1037H: Security(SAM+线段树合并)

    题意:给定字符串S:  Q次询问,每次询问给出(L,R,T),让你在S[L,R]里面找一个字典序最小的子串,其字典序比T大. 没有则输出-1: 思路:比T字典序大,而且要求字典最小,显然就是在T的尾巴 ...

  3. 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree

    原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...

  4. UOJ#395. 【NOI2018】你的名字 字符串,SAM,线段树合并

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ395.html 题解 记得同步赛的时候这题我爆0了,最暴力的暴力都没调出来. 首先我们看看 68 分怎么做 ...

  5. Codeforces 700E. Cool Slogans 字符串,SAM,线段树合并,动态规划

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF700E.html 题解 首先建个SAM. 一个结论:对于parent树上任意一个点x,以及它所代表的子树内任 ...

  6. loj#2059. 「TJOI / HEOI2016」字符串 sam+线段树合并+倍增

    题意:给你一个子串,m次询问,每次给你abcd,问你子串sa-b的所有子串和子串sc-d的最长公共前缀是多长 题解:首先要求两个子串的最长公共前缀就是把反过来插入变成最长公共后缀,两个节点在paren ...

  7. 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... ...

  8. CF700E:Cool Slogans(SAM,线段树合并)

    Description 给你一个字符串,如果一个串包含两个可有交集的相同子串,那么这个串的价值就是子串的价值+1.问你给定字符串的最大价值子串的价值. Input 第一行读入字符串长度$n$,第二行是 ...

  9. [NOI2018]你的名字(SAM+线段树合并)

    考虑l=1,r=n的68分,对S和T建SAM,对T的SAM上的每个节点,计算它能给答案带来多少贡献. T上节点x代表的本质不同的子串数为mx[x]-mx[fa[x]],然后需要去掉所代表子串与S的最长 ...

随机推荐

  1. 日期控件传到后台异常。日期数据格式是 Date 还是 String?

    问题:日期控件的时间,传到Controller层直接异常. 前台日期格式:YYYY/MM/DD,后台Java定义的时间类型:Date. 解决: 方法一:原因是Controller层的参数类型定义为 D ...

  2. idea查看源码没有注释的问题

    进入idea的设置 勾选这两个 然后重新导入 页面的右上角有个下载download source的提示,点击下载即可 然后页面就要源码注释了

  3. kafka2.10集群搭建(一)

    一.kafka集群搭建 1.上传解压 2.配置文件的配置 1.修改 server.properties文件 broker.id=11 #192.168.199.11 #21 一般使用ip后三位 lis ...

  4. 更改oracle RAC public ip,vip,scan ip和private ip

    更改oracle RAC public ip,vip,scan ip和private ip oifcfg - Oracle 接口配置工具 用法:  oifcfg iflist [-p [-n]]    ...

  5. Shell脚本之流程控制(if、for、while)

    if 判断 if语句的三种格式: (1)if (2)if else (3)if elif else 语法格式如下: #if 语法格式 if 条件 then 命令1... 命令2... fi #if e ...

  6. SpringBoot 项目如何在tomcat容器中运行

    一. SpringBoot内嵌容器的部署方式 SpringBoot内部默认提供内嵌的tomcat容器,所以可以直接打成jar包,丢到服务器上的任何一个目录,然后在当前目录下执行java -jar de ...

  7. JAVA开发者大会:拍拍贷MQ系统原理与应用

    --喜欢记得关注我哟[shoshana]-- 前记: 5月12号参加了JAVA开发者大会,就<拍拍贷消息系统原理及应用> 作者:李乘胜老师 关于PMQ的分享整理一下笔记以及笔记的思考 和复 ...

  8. hyper-v虚拟机centos7网络配置

    原文地址:https://jingyan.baidu.com/article/91f5db1b0279bd1c7e05e377.html hyper-v安装了centos7之后并不能上网,这里简单介绍 ...

  9. fiddler笔记:快捷工具栏

    WinConfig:   Comment 为所有选中的Session添加Comment. Replay Replay+ctrl 重新发送请求,而不包括任何条件请求头. Replay+shift 指定每 ...

  10. 标准库中最值得关注的两个 装饰器是 lru_cache 和全新的 singledispatch(Python 3.4 新增)

    clock 装饰器 def clock(func): @functools.wraps(func) def clocked(*args, **kwargs): t0 = time.perf_count ...