【LOJ 6041】「雅礼集训 2017 Day7」事情的相似度
Description
人的一生不仅要靠自我奋斗,还要考虑到历史的行程。
历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势。
你发现在历史的不同时刻,不断的有相同的事情发生。比如,有两个人同时在世纪之交 11 年的时候上台,同样喜欢与洋人谈笑风生,同样提出了以「三」字开头的理论。
你发现,一件事情可以看成是这个 01 串的一个前缀,这个前缀最右边的位置就是这个事情的结束时间。
两件事情的相似度可以看成,这两个前缀的最长公共后缀长度。
现在你很好奇,在一段区间内结束的事情中最相似的两件事情的相似度是多少呢?
Input
第一行两个整数 n、m,表示串长和询问个数。
第二行长度为 n 的 01 串,表示历史的行程。
接下来 m 行,每行两个正整数 l 、r 表示询问的区间,包括端点,保证1≤l<r≤n。
Output
输出 m 行,对每个询问输出一个整数表示最大的相似度。
建出原串的SAM,则两个前缀的最长公共后缀为他们在parent树上的lca,问题转化为求区间内前缀两两lca深度的最大值。
将询问离线,按右端点从小到大排序。我们考虑每次加入一个字母,就将他们在parent树上到根节点的路径打上他们的标记。往根节点跑的过程中,若遇到了以前打的标记,则该节点为旧标记与新标记的lca。贪心可得应把标记尽量覆盖为较大的值。用树状数组来统计答案,下标为左端点,每次查询下标大于等于该询问左端点的最大深度。向根跑的过程中每一次遇到旧标记,就在树状数组上更新答案,并给该节点打上新标记。
往根节点跑的过程实际上就是LCT的access。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define LL long long
using namespace std;
const int N=1e5+;
int n,m,r,last,size,root;
int p[N],mx[N],ans[N],num[N];
int c[N*][],fa[N*],v[N*],tag[N*];
char s[N];
vector<int> q[N];
struct sam{int mx,fa,ch[];}t[N*];
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int lowbit(int x){return x&(-x);}
void modify(int x,int v){x=n-x+;while(x<=n)mx[x]=max(mx[x],v),x+=lowbit(x);}
int query(int x){x=n-x+;int ans=;while(x)ans=max(ans,mx[x]),x-=lowbit(x);return ans;}
void ins(int c,int id)
{
int np=++size;num[id]=np;
t[np].mx=t[last].mx+;
int x=last;last=np;
while(x&&!t[x].ch[c])t[x].ch[c]=np,x=t[x].fa;
if(!x)t[np].fa=root;
else
{
int y=t[x].ch[c];
if(t[y].mx==t[x].mx+)t[np].fa=y;
else
{
int nq=++size;
t[nq]=t[y];t[nq].mx=t[x].mx+;
t[y].fa=t[np].fa=nq;
while(x&&t[x].ch[c]==y)t[x].ch[c]=nq,x=t[x].fa;
}
}
}
bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
void change(int x,int val){v[x]=tag[x]=val;}
void down(int x)
{
if(!tag[x])return;
if(c[x][])change(c[x][],tag[x]);
if(c[x][])change(c[x][],tag[x]);
tag[x]=;
}
void rotate(int x)
{
int y=fa[x],z=fa[y],l,r;
if(c[y][]==x)l=;else l=;r=l^;
if(!isroot(y)){if(c[z][]==y)c[z][]=x;else c[z][]=x;}
fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
c[y][l]=c[x][r];c[x][r]=y;
}
void relax(int x){if(!isroot(x))relax(fa[x]);down(x);}
void splay(int x)
{
relax(x);
while(!isroot(x))
{
int y=fa[x],z=fa[y];
if(!isroot(y))
{
if((c[y][]==x)^(c[z][]==y))rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x,int val)
{
int o=;
while(x)
{
splay(x);modify(v[x],t[x].mx);
c[x][]=o;o=x;x=fa[x];
}
tag[o]=v[o]=val;
}
void build(){for(int i=;i<=size;i++)fa[i]=t[i].fa;}
int main()
{
n=read();m=read();
scanf("%s",s+);
for(int i=;i<=m;i++)
{
p[i]=read();r=read();
q[r].push_back(i);
}
last=size=root=;
for(int i=;i<=n;i++)ins(s[i]-'',i);
build();
for(int i=;i<=n;i++)
{
access(num[i],i);
int sz=q[i].size();
for(int j=;j<sz;j++)
{
int x=q[i][j];
ans[x]=query(p[x]);
}
}
for(int i=;i<=m;i++)printf("%d\n",ans[i]);
return ;
}
【LOJ 6041】「雅礼集训 2017 Day7」事情的相似度的更多相关文章
- 【刷题】LOJ 6041 「雅礼集训 2017 Day7」事情的相似度
题目描述 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的有相同的事情发 ...
- LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度
我可以大喊一声这就是个套路题吗? 首先看到LCP问题,那么套路的想到SAM(SA的做法也有) LCP的长度是它们在parent树上的LCA(众所周知),所以我们考虑同时统计多个点之间的LCA对 树上问 ...
- loj#6041. 「雅礼集训 2017 Day7」事情的相似度(SAM set启发式合并 二维数点)
题意 题目链接 Sol 只会后缀数组+暴躁莫队套set\(n \sqrt{n} \log n\)但绝对跑不过去. 正解是SAM + set启发式合并 + 二维数点/ SAM + LCT 但是我只会第一 ...
- loj#6041. 「雅礼集训 2017 Day7」事情的相似度(后缀自动机+启发式合并)
题面 传送门 题解 为什么成天有人想搞些大新闻 这里写的是\(yyb\)巨巨说的启发式合并的做法(虽然\(LCT\)的做法不知道比它快到哪里去了--) 建出\(SAM\),那么两个前缀的最长公共后缀就 ...
- LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度 LCT+SAM+线段树
Code: #include<bits/stdc++.h> #define maxn 200003 using namespace std; void setIO(string s) { ...
- #6041. 「雅礼集训 2017 Day7」事情的相似度 [set启发式合并+树状数组扫描线]
SAM 两个前缀的最长后缀等价于两个点的 \(len_{lca}\) , 题目转化为求 \(l \leq x , y \leq r\) , \(max\{len_{lca(x,y)}\}\) // p ...
- 「雅礼集训 2017 Day7」事情的相似度
「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...
- LOJ6041. 「雅礼集训 2017 Day7」事情的相似度 [后缀树,LCT]
LOJ 思路 建出反串的后缀树,发现询问就是问一个区间的点的\(lca\)的深度最大值. 一种做法是dfs的时候从下往上合并\(endpos\)集合,发现插入一个点的时候只需要把与前驱后继的贡献算进去 ...
- 【loj6041】「雅礼集训 2017 Day7」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组
题目描述 给你一个长度为 $n$ 的01串,$m$ 次询问,每次询问给出 $l$ .$r$ ,求从 $[l,r]$ 中选出两个不同的前缀的最长公共后缀长度的最大值. $n,m\le 10^5$ 题解 ...
随机推荐
- 黑阔主流攻防之不合理的cookie验证方式
最近博主没事干中(ZIZUOZISHOU),于是拿起某校的习题研究一番,名字很6,叫做黑阔主流攻防习题 虚拟机环境经过一番折腾,配置好后,打开目标地址:192.168.5.155 如图所示 这里看出题 ...
- jquery字符串操作
目的:把自己常用到的jquery操作字符串总结一下 w3cSchool关于js字符串的整理:有需要的时候可以查 http://www.w3school.com.cn/js/jsref_obj_stri ...
- 如何通过Git将写好的项目发布到github上
1.在GitHub上创建新的项目文件 2.创建之后会进入新的页面,看到如下图的内容,将地址记下来 3.打开Git 4.进入项目本地所在目录 5.输入:git init 这个意思是在当前项目的目录中生成 ...
- ASP.NET MVC 自定义模型绑定1 - 自动把以英文逗号分隔的 ID 字符串绑定成 List<int>
直接贴代码了: CommaSeparatedModelBinder.cs using System; using System.Collections; using System.Collection ...
- Linux:Day9(上) 压缩工具
压缩.解压缩及归档工具 compress/uncompress:.Z # 现在已经很少在见到了 gzip/gunzip:.gz bzip2/bunzip2:.bz2 xz/unxz:.xz # 目前推 ...
- VS2019 实用操作
本文列出了在编写程序过程中的几个非常实用的操作方式,通过这些操作方式,可以在一定程度上减少重复操作.提高编码效率.改善编程体验. 列模式操作 列操作是一项很常用且实用的功能,可以一次性修改不同的行. ...
- 企业推动移动化战略中为什么需要Moli?
随着科技的进步,计算能力程指数上升,引爆人工智能的大发展,人类社会开始步进入智能时代.与此同时,端能力将演进到第三代,全面参与智能边缘计算,从PC互联到移动互联到万物互联,历史在快速演进:主流技术向物 ...
- PHP7.0-PHP7.3新特性与变更
到目前为止,PHP7发布已经升级到7.3,本文来总结一下每个版本的变更与新特性 PHP7.0 1. 组合比较符 (<=>) 组合比较符号用于比较两个表达式.当$a小于.等于或大于$b时它分 ...
- LeetCode_p150_逆波兰表达式计算/后缀表达式计算
有效的运算符包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说明: 整数除法只保留整数部分. 给定逆波兰表达式总是有效的.换句话说,表达式总会得出有效数值且不存在除 ...
- vue-cli全局安装
一.安装node.js a).不确定自己时候安装了node.js可以在控制台当中输入node -v来查看当前是否已经存在 如果看到输出了版本信息,那么证明已经有了node.js b).如果看到node ...