TJOI2016 字符串
字符串
佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CEO,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?
1<=n,m<=100,000,
分析
参照Dream_maker_yk和wzj的题解。
查前缀我们就把串反着插入,这时候状态该有一个left集合。
在这个反串的SAM上,两个点的最长公共前缀是两个点parent树上lca的len.
我们对于parent树中的每个节点,都维护他的子树中出现了字符串中的哪些节点,即left集合。这个可用线段树合并。
二分答案x,倍增找到c的祖先中len>=x的最浅的节点,判断该节点的left集合中是否出现了[a,b-x+1]。
时间复杂度\(O(n \log^2 n)\)
co int N=2e5;
namespace T{ // Interval Tree
int tot,root[N],lc[N*20],rc[N*20];
void insert(int&x,int l,int r,int p){
x=++tot;
if(l==r) return;
int mid=l+r>>1;
if(p<=mid) insert(lc[x],l,mid,p);
else insert(rc[x],mid+1,r,p);
}
int merge(int x,int y){
if(!x||!y) return x+y;
int z=++tot;
lc[z]=merge(lc[x],lc[y]),rc[z]=merge(rc[x],rc[y]);
return z;
}
int query(int x,int l,int r,int ql,int qr){
if(!x) return 0;
if(ql<=l&&r<=qr) return 1;
int mid=l+r>>1;
if(qr<=mid) return query(lc[x],l,mid,ql,qr);
if(ql>mid) return query(rc[x],mid+1,r,ql,qr);
return query(lc[x],l,mid,ql,qr)||query(rc[x],mid+1,r,ql,qr);
}
}
int n,m;
char s[N];
int last=1,tot=1; // Suffix Automaton
int ch[N][26],fa[N],len[N],pos[N]; // pos: out->in
void extend(int c,int po){
int p=last,cur=last=++tot;
len[cur]=len[p]+1,pos[po]=cur;
T::insert(T::root[cur],1,n,po);
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
if(!p) fa[cur]=1;
else{
int q=ch[p][c];
if(len[q]==len[p]+1) fa[cur]=q;
else{
int clone=++tot;
memcpy(ch[clone],ch[q],sizeof ch[q]);
fa[clone]=fa[q],len[clone]=len[p]+1;
fa[cur]=fa[q]=clone;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
}
}
}
int cnt[N],ord[N],anc[N][19];
int check(int x,int a,int b,int p){
for(int i=18;i>=0;--i)
if(len[anc[p][i]]>=x) p=anc[p][i];
return T::query(T::root[p],1,n,a,b-x+1);
}
int main(){
read(n),read(m);
scanf("%s",s+1);
for(int i=n;i>=1;--i) extend(s[i]-'a',i);
for(int i=1;i<=tot;++i) ++cnt[len[i]];
for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
for(int i=1;i<=tot;++i) ord[cnt[len[i]]--]=i;
for(int i=tot;i;--i){
int u=ord[i];
T::root[fa[u]]=T::merge(T::root[fa[u]],T::root[u]);
}
for(int i=1;i<=tot;++i){ // edit 1: order isn't changeable
int u=ord[i];
anc[u][0]=fa[u];
for(int j=1;j<=18;++j) anc[u][j]=anc[anc[u][j-1]][j-1];
}
for(int a,b,c,d;m--;){
read(a),read(b),read(c),read(d);
int l=0,r=std::min(b-a+1,d-c+1);
while(l<r){
int mid=l+r+1>>1;
if(check(mid,a,b,pos[c])) l=mid;
else r=mid-1;
}
printf("%d\n",l);
}
return 0;
}
TJOI2016 字符串的更多相关文章
- 洛谷P4094 - [TJOI2016]字符串
Portal Description 给出一个字符串\(s(|s|\leq10^5)\)和\(m\)次询问,每次询问子串\(s[x_1..x_2]\)的所有子串和\(s[y_1..y_2]\)的最长公 ...
- BZOJ 4556 [HEOI2016/TJOI2016]字符串
BZOJ 4556 [HEOI2016/TJOI2016]字符串 其实题解更多是用后缀数组+数据结构的做法,貌似也不好写. 反正才学了 sam 貌似比较简单的做法. 还是得先二分,然后倍增跳到 $ s ...
- P4094 [HEOI2016/TJOI2016]字符串 后缀数组+主席树+二分答案
$ \color{#0066ff}{ 题目描述 }$ 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须 ...
- [HEOI2016/TJOI2016]字符串
嘟嘟嘟 今天复习一下SAM. lcp固然不好做,干脆直接翻过来变成后缀.首先答案一定满足单调性,所以我们二分lcp的长度\(mid\),然后判断\(s[d \ldots d + mid - 1]\)是 ...
- [HEOI2016/TJOI2016]字符串(后缀数组+二分+主席树/后缀自动机+倍增+线段树合并)
后缀数组解法: 先二分最长前缀长度 \(len\),然后从 \(rnk[c]\) 向左右二分 \(l\) 和 \(r\) 使 \([l,r]\) 的 \(height\geq len\),然后在主席树 ...
- 【[HEOI2016/TJOI2016]字符串】
码农题啊 上来先无脑一个\(SA\)的板子,求出\(SA\)和\(het\)数组 我们只需要从\(sa[i]\in[a,b]\)的所有\(i\)中找到一个\(i\)使得\(sa[i]\)和\(rk[c ...
- luoguP4094 [HEOI2016/TJOI2016]字符串
题意 考虑二分答案\(mid\),现在我们要判断\(s[c...c+mid-1]\)是否在\(s[a...b]\)出现过. 首先找到\(s[c...c+mid-1]\)所在的状态: 建出\(paren ...
- BZOJ4556 HEOI2016/TJOI2016字符串 (后缀树+主席树)
二分答案后相当于判断一个区间的后缀与某个后缀的最长公共前缀是否能>=ans.建出后缀树,在上述问题中后者所在节点向上倍增的跳至len>=ans的最高点,然后相当于查询子树中是否有该区间的节 ...
- HEOI2016/TJOI2016 字符串问题
题目链接:戳我 非常不好意思,因为想要排版,所以今天先只把代码贴出来,明天补题解. 40pts暴力:直接暴力匹配 #include<iostream> #include<cstrin ...
随机推荐
- ActiveMQ学习教程
一.activemq安装 官网地址:https://activemq.apache.org/ 具体安装过程不赘述,解压即安装, 二.使用 activemq有queue和topic两种模式, 我们以qu ...
- 腾讯明眸极速高清升级2.0,助力韩国赛事超高清5G直播
近期,由腾讯云联合韩国CUDO通信研究所及intel推出的tile方式的viewport流服务编码,已正式通过测试.届时韩国最新5G网络将基于腾讯明眸-极速高清2.0和腾讯云直播产品能力,在韩国国内率 ...
- FineUI window弹层设置
需在页面先设置 <f:Window ID="Window1" runat="server" Height="600px" Widt ...
- spring整合quartz报错
今天spring整合quartz报错,最后一步步排查,发现是和redis依赖冲突,最后redis升级了一下,问题解决. 总结:发现问题,逐一排查,如果是整合问题,报类加载不到的错误,大概率是和其他组件 ...
- ScheduledExecutorService调度线程池运行几次后停止某一个线程
开发中偶尔会碰到一些轮询需求,比如我碰到的和银行对接,在做完某一个业务后银行没有同步给到结果,这时候就需要查询返回结果,我们的需求是5分钟一次,查询3次,3次过后如果没有结果则T+1等银行的文件,对于 ...
- laravel使用辅助函数url()引入js和css静态文件
使用laravel框架时可以将静态文件如,js文件,css文件,放到resources文件夹下的js下,当然也可以放到public文件夹下的js文件夹下,publi文件夹下默认情况下是没有css,js ...
- python学习67-面向对象-封装
封装 1.什么是封装? 根据名字寓意为:把一个东西装起来,然后密封,类似这样的面向对象的编程为封装. 真正的封装是明确的区别内外,只能在内部用,外部无法调用. 2. 举例: class Car: _s ...
- AVR单片机教程——数字输入
我们已经学习了如何使用按键和拨动开关,不知你有没有好奇 button_down 和 switch_status 等函数是如何实现的.本篇教程带你一探究竟,让我们从按键的原理开始. 在原理图中,按键的符 ...
- 【scratch3.0教程】2.1 涂鸦花朵
第4课 涂鸦花朵 1.编程前的准备 在设计一个作品之前,必须先策划一个脚本,然后再根据脚本,收集或制作素材(图案,声音等)接着就可以启动Scratch,汇入角色,舞台,利用搭程序积木的方式编辑程 ...
- application.yml报错:a global security auto-configuration is now provided
报错原因: Spring Boot 1.5升级到2.0改动 security开头的配置及management.security均已过期 Actuator 配置属性变化 Endpoint变化 参考来源: ...