题意:给定字符串S;  Q次询问,每次询问给出(L,R,T),让你在S[L,R]里面找一个字典序最小的子串,其字典序比T大。 没有则输出-1;

思路:比T字典序大,而且要求字典最小,显然就是在T的尾巴加一个很小的字符,如果不存在,则依次删去尾巴,直到“存在”。

而“存在”是指,前缀lim+一个字符‘x’后存在于[L+lim,R]中, 所以我们需要预处理出所有点的endpos,这个用线段树合并就可以了。

注意这里是每一个节点都要记录,所以和普通的启发式合并不太一样,这里需要每次新开一个节点。

#include<bits/stdc++.h>
#define rep2(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
char c[maxn]; int rt[maxn],N,tot;
struct in{
int L,R,sum;
}s[maxn*];
void ins(int &now,int L,int R,int p)
{
if(!now) now=++tot; s[now].sum++;
if(L==R) return ; int Mid=(L+R)>>;
if(p<=Mid) ins(s[now].L,L,Mid,p);
else ins(s[now].R,Mid+,R,p);
}
int merge(int x,int y)
{
if(!x||!y) return x|y;
int now=++tot;
s[now].L=merge(s[x].L,s[y].L);
s[now].R=merge(s[x].R,s[y].R);
s[now].sum=s[s[now].L].sum+s[s[now].R].sum;
return now;
}
bool query(int Now,int L,int R,int l,int r)
{
if(!Now||l>r) return false;
if(l<=L&&r>=R) return s[Now].sum;
int Mid=(L+R)>>;
if(l<=Mid&&query(s[Now].L,L,Mid,l,r)) return true;
if(r>Mid) return query(s[Now].R,Mid+,R,l,r);
return 0;
}
struct SAM{
int ch[maxn][],fa[maxn],maxlen[maxn],cnt,last;
int a[maxn],b[maxn];
void init()
{
cnt=last=;
memset(ch[],,sizeof(ch[]));
}
int add(int x,int id)
{
int np=++cnt,p=last; last=np;
ins(rt[np],,N,id);
maxlen[np]=maxlen[p]+; memset(ch[np],,sizeof(ch[np]));
while(p&&!ch[p][x]) ch[p][x]=np,p=fa[p];
if(!p) fa[np]=;
else {
int q=ch[p][x];
if(maxlen[q]==maxlen[p]+) fa[np]=q;
else {
int nq=++cnt; maxlen[nq]=maxlen[p]+;
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
while(p&&ch[p][x]==q) ch[p][x]=nq,p=fa[p];
}
}
}
void sort()
{
rep(i,,cnt) a[i]=;
rep(i,,cnt) a[maxlen[i]]++;
rep(i,,cnt) a[i]+=a[i-];
rep(i,,cnt) b[a[maxlen[i]]--]=i;
for(int i=cnt;i>=;i--) {
int x=b[i];
if(fa[x]) rt[fa[x]]=merge(rt[fa[x]],rt[x]);
}
}
}T;
int pos[maxn],Q;
void solve()
{
int L,R,len,fcy;
scanf("%d%d%s",&L,&R,c+);
len=strlen(c+);
int now=,lim=len; c[len+]='a'-;
rep(i,,len) {
if(T.ch[now][c[i]-'a']) now=T.ch[now][c[i]-'a'];
else { lim=i-; break;}
pos[i]=now;
}
fcy=-; pos[]=;
for(int i=lim;i>=&&fcy==-;i--){
for(int j=c[i+]-'a'+;j<;j++){
int v=T.ch[pos[i]][j];
if(!v) continue;
if(query(rt[v],,N,L+i,R)) {
fcy=i+; c[fcy]='a'+j;
break;
}
}
}
if(fcy==-) puts("-1");
else { rep(i,,fcy) putchar(c[i]); puts(""); }
}
int main()
{
T.init();
scanf("%s",c+); N=strlen(c+);
rep(i,,N) T.add(c[i]-'a',i);
T.sort();
scanf("%d",&Q);
while(Q--) solve();
return ;
}

CodeForces - 1037H: Security(SAM+线段树合并)的更多相关文章

  1. CF1037H Security——SAM+线段树合并

    又是一道\(SAM\)维护\(endpos\)集合的题,我直接把CF700E的板子粘过来了QwQ 思路 如果我们有\([l,r]\)对应的\(SAM\),只需要在上面贪心就可以了.因为要求的是字典序比 ...

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

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

  3. Codeforces 1276F - Asterisk Substrings(SAM+线段树合并+虚树)

    Codeforces 题面传送门 & 洛谷题面传送门 SAM hot tea %%%%%%% 首先我们显然可以将所有能够得到的字符串分成六类:\(\varnothing,\text{*},s, ...

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. java对象转变为map

    直接上代码 package com.**.**.**.common; import com.**.**.**.util.JsonUtils; import org.springframework.be ...

  2. Queue介绍

    美人如斯! 前言 队列是一种先进先出(FIFO)的数据结构,与生活中的排队类似,即先来先被服务,这样的特点决定了其具有一定的优先级含义,可以被用于任务调度等场景.队列模型如图: 图1.队列模型 jav ...

  3. golang学习笔记--函数和方法

    在go中,函数类型是一等类型,这意味着可以吧函数当做一个值来传递和使用. func divide(dividend int,divisor int)(int,error){ //省略部分代码 } 参数 ...

  4. Java多线程分批发送消息的小例子

    需求: 假设有10万个用户,现在节假日做活动,需要给每个用户发送一条活动短信,为了提高程序的效率,建议使用多线程分批发送. 这里值得注意的是: 每开一个线程都会占用CPU的资源,所以线程根据所需要的条 ...

  5. UDP比TCP好用的优势

    网络带宽环境变好 在2007年至2015年间,网络的带宽飞速发展,从1.5Mbps的带宽增加到5.1Mbps的带宽,足足增加了4倍,网络环境快速.稳定,所以UDP的丢包率 下降至5%以下,越来越好的网 ...

  6. C#多线程的同步与通信

    C#中使用lock和Monitor控制多线程对资源的使用,最常见的生产者和消费者问题就是多线程同步和通信的经典例子.了解C#多线程的同步与通信. 一.关于lock和Monitor lock可以把一段代 ...

  7. fail fast和fail safe策略

    优先考虑出现异常的场景,当程序出现异常的时候,直接抛出异常,随后程序终止 import java.util.ArrayList; import java.util.Collections; impor ...

  8. C#读写设置修改调整UVC摄像头画面-对比度

    有时,我们需要在C#代码中对摄像头的对比度进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄 ...

  9. js/jquery键盘事件及keycode大全

    js/jquery的键盘事件分为keypress.keydown和keyup事件 一.键盘事件 1.keydown()事件当按钮被按下时,发生 keydown 事件. 2.keypress()事件ke ...

  10. String常用使用方法,1.创建string的常用3+1种方式,2.引用类型使用==比较地址值,3.String当中获取相关的常用方法,4.字符串的截取方法,5.String转换常用方法,6.切割字符串----java

    一个知识点使用一个代码块方便查看 1.创建string的常用3+1种方式 /* 创建string的常用3+1种方式 三种构造方法 public String():创建一个空字符串,不含有任何内容: p ...