题解「雅礼集训 2017 Day7」事情的相似度
Description
给出一个长度为 \(n\) 的 \(01\) 串为 \(s\),设 \(t_i\) 为 \(s_{1,2,..,i}\),有 \(m\) 次查询,每次查询给出 \(l,r\),求 \([l,r]\) 之间 \(t_i\) 的最长公共后缀长度的最大值。
\(n,m\le 10^5\)
Solution
本来不想写题解的,但想了想还是写一下吧。
不难想到,假设 \(f_i\) 为 \(t_i\) 在后缀自动机上对应的点,那么就相当于查询:
\]
考虑到在线不好搞,所以我们离线下来。然后你发现按左端点排序根本就不好做(不要问我怎么知道的),然后你发现按右端点排序之后就好做了。
我们可以在加入一个点的时候把 \(\text{parent}\) 树上都标记一下,那么如果过程中对于点 \(u\),如果已经标记过 \(i\) 了,那么说明对于当前右端点,左端点 \(\le i\) 的区间 \(u\) 都可以产生贡献,就可以树状数组修改一下。由此我们也可以看出,我们需要保存的是最新标记的标记。
复杂度显然是 \(\Theta(n\log^2n)\) 。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 200005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
char s[MAXN];
int n,m,ans[MAXN];
struct Bit_Tree{
int maxn[MAXN];
int lowbit (int x){return x & (-x);}
void modify (int x,int v){x = n - x + 1;for (Int i = x;i <= n;i += lowbit (i)) maxn[i] = max (maxn[i],v);}
int query (int x){x = n - x + 1;int ans = 0;for (Int i = x;i;i -= lowbit (i)) ans = max (ans,maxn[i]);return ans;}
}T1;
struct node{
int ind,qL,qR;
bool operator < (const node &p)const{return qR < p.qR;}
};
vector <node> S[MAXN];
int lst = 1,cnt = 1,ch[MAXN][2],len[MAXN],git[MAXN],fail[MAXN];
void extend (int c){
int f = lst,q = ++ cnt;lst = q,len[q] = len[f] + 1;
while (f && !ch[f][c]) ch[f][c] = q,f = fail[f];
if (!f) fail[q] = 1;
else{
int x = ch[f][c];
if (len[x] == len[f] + 1) fail[q] = x;
else{
int p = ++ cnt;
fail[p] = fail[x],len[p] = len[f] + 1,memcpy (ch[p],ch[x],sizeof (ch[p]));
fail[x] = fail[q] = p;while (f && ch[f][c] == x) ch[f][c] = p,f = fail[f];
}
}
}
struct LCT{
int id[MAXN],fa[MAXN],son[MAXN][2];
bool rnk (int x){return son[fa[x]][1] == x;}
bool Isroot (int x){return son[fa[x]][rnk(x)] != x;}
void rotate (int x){
int y = fa[x],z = fa[y],k = rnk(x),w = son[x][!k];
if (!Isroot (y)) son[z][rnk(y)] = x;son[x][!k] = y,son[y][k] = w;
if (w) fa[w] = y;fa[x] = z,fa[y] = x;
}
void Pushdown (int x){
if (son[x][0]) id[son[x][0]] = id[x];
if (son[x][1]) id[son[x][1]] = id[x];
}
void Pushall (int x){
if (!Isroot (x)) Pushall (fa[x]);
Pushdown (x);
}
void Splay (int x){
Pushall (x);
while (!Isroot (x)){
int y = fa[x];
if (!Isroot (y)) rotate (rnk(x) == rnk(y) ? y : x);
rotate (x);
}
}
void Access (int x,int now){
for (Int y = 0;x;x = fa[y = x]){
Splay (x);
if (id[x]) T1.modify (id[x],len[x]);
son[x][1] = y,id[x] = now;
}
}
}T2;
signed main(){
read (n,m),scanf ("%s",s + 1);
for (Int i = 1;i <= n;++ i) extend (s[i] - '0'),git[i] = lst;
for (Int i = 1,qL,qR;i <= m;++ i) read (qL,qR),S[qR].push_back (node{i,qL,qR});
for (Int i = 1;i <= cnt;++ i) T2.fa[i] = fail[i];
for (Int i = 1;i <= n;++ i){
T2.Access (git[i],i);
for (node g : S[i]) ans[g.ind] = T1.query (g.qL);
}
for (Int i = 1;i <= m;++ i) write (ans[i]),putchar ('\n');
return 0;
}
题解「雅礼集训 2017 Day7」事情的相似度的更多相关文章
- 「雅礼集训 2017 Day7」事情的相似度
「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...
- 【刷题】LOJ 6041 「雅礼集训 2017 Day7」事情的相似度
题目描述 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的有相同的事情发 ...
- 【LOJ 6041】「雅礼集训 2017 Day7」事情的相似度
Description 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的 ...
- 【loj6041】「雅礼集训 2017 Day7」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组
题目描述 给你一个长度为 $n$ 的01串,$m$ 次询问,每次询问给出 $l$ .$r$ ,求从 $[l,r]$ 中选出两个不同的前缀的最长公共后缀长度的最大值. $n,m\le 10^5$ 题解 ...
- loj#6041. 「雅礼集训 2017 Day7」事情的相似度(后缀自动机+启发式合并)
题面 传送门 题解 为什么成天有人想搞些大新闻 这里写的是\(yyb\)巨巨说的启发式合并的做法(虽然\(LCT\)的做法不知道比它快到哪里去了--) 建出\(SAM\),那么两个前缀的最长公共后缀就 ...
- 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 但是我只会第一 ...
- 【LOJ6041】「雅礼集训 2017 Day7」事情的相似度(用LCT维护SAM的parent树)
点此看题面 大致题意: 给你一个\(01\)串,每次询问前缀编号在一段区间内的两个前缀的最长公共后缀的长度. 离线存储询问 考虑将询问离线,按右端点大小用邻接表存下来(直接排序当然也可以啦). 这样的 ...
- LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度 LCT+SAM+线段树
Code: #include<bits/stdc++.h> #define maxn 200003 using namespace std; void setIO(string s) { ...
随机推荐
- 移动端常用单位——rem
移动端常用单位: ①px:像素大小,固定值 ②%:百分比 ③em(不常用,但是在首行缩进时可以使用):相对自身的font大小(当自身的字体大小也是em做单位时,才会以父元素的字体大小为基准单位) ④r ...
- MySQL-SQL基础1
p.p1 { margin: 0; font: 11px Menlo; background-color: rgba(128, 128, 128, 0.5); min-height: 13px } p ...
- Shell脚本基础及基本常用命令
1.概述 脚本语言(shell.python):解释性语言,用解释器解释 运行效率低 | c.java:描述性语言,运行效率高 以.sh结尾会有高亮显示 执行: sh hello.sh 或者 chmo ...
- Linux服务器JDK的安装
JDK安装 开发java程序必须要的环境 下载JDK rpm. 安装环境 #检测当前系统是否安装Java环境 java -version #如果有就需要卸载 #rpm -qa|grep jdk #检测 ...
- noip模拟48
A. Lighthouse 很明显的容斥题,组合式与上上场 \(t2\) 一模一样 注意判环时长度为 \(n\) 的环是合法的 B. Miner 题意实际上是要求偶拉路 对于一个有多个奇数点的联通块, ...
- adb 常用命令大全(6)- 模拟按键输入
语法格式 input [<source>] <command> [<arg>...] 物理键 # 电源键 adb shell input keyevent 26 # ...
- STP(生成树)的概述和工作原理
一.STP的简介 二.STP的概述 三.STP的工作原理 四.生成树的算法 五.BPDU(桥协议数据单元) 六.STP收敛 TP简介 STP - Spanning Tree Protocol(生成树协 ...
- 树莓派的kodi设置遥控器的方法
首先你需要买一个红外接收器,根据卖家的文档,插到树莓派的GPIO串口上, 我的红外接收器是18入口,17出口, 所以我的config.txt文件设置如下 dtoverlay=lirc-rpi,gpio ...
- Django学习day15BBS项目开发4.0(完结)
每日测验 """ 今日考题: 1.简述自定义标签,过滤器,inclusion_tag的方法,并简要说一说三者的特点及响应流程 2.简述个人侧边栏展示及筛选业务逻辑 3.简 ...
- ecshop调用指定分类热销-新品-精品
在模板页里首页写上代码: <?php$children = get_children(16);//此处为产品分类ID$smarty->assign( 'bestGoods1 ...