题目传送门

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\) 在后缀自动机上对应的点,那么就相当于查询:

\[\max\{\text{deep}(\text{lca}(f_i,f_j))\},l\le i,j\le r
\]

考虑到在线不好搞,所以我们离线下来。然后你发现按左端点排序根本就不好做(不要问我怎么知道的),然后你发现按右端点排序之后就好做了。

我们可以在加入一个点的时候把 \(\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」事情的相似度的更多相关文章

  1. 「雅礼集训 2017 Day7」事情的相似度

    「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...

  2. 【刷题】LOJ 6041 「雅礼集训 2017 Day7」事情的相似度

    题目描述 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的有相同的事情发 ...

  3. 【LOJ 6041】「雅礼集训 2017 Day7」事情的相似度

    Description 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的 ...

  4. 【loj6041】「雅礼集训 2017 Day7」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组

    题目描述 给你一个长度为 $n$ 的01串,$m$ 次询问,每次询问给出 $l$ .$r$ ,求从 $[l,r]$ 中选出两个不同的前缀的最长公共后缀长度的最大值. $n,m\le 10^5$ 题解 ...

  5. loj#6041. 「雅礼集训 2017 Day7」事情的相似度(后缀自动机+启发式合并)

    题面 传送门 题解 为什么成天有人想搞些大新闻 这里写的是\(yyb\)巨巨说的启发式合并的做法(虽然\(LCT\)的做法不知道比它快到哪里去了--) 建出\(SAM\),那么两个前缀的最长公共后缀就 ...

  6. LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度

    我可以大喊一声这就是个套路题吗? 首先看到LCP问题,那么套路的想到SAM(SA的做法也有) LCP的长度是它们在parent树上的LCA(众所周知),所以我们考虑同时统计多个点之间的LCA对 树上问 ...

  7. loj#6041. 「雅礼集训 2017 Day7」事情的相似度(SAM set启发式合并 二维数点)

    题意 题目链接 Sol 只会后缀数组+暴躁莫队套set\(n \sqrt{n} \log n\)但绝对跑不过去. 正解是SAM + set启发式合并 + 二维数点/ SAM + LCT 但是我只会第一 ...

  8. 【LOJ6041】「雅礼集训 2017 Day7」事情的相似度(用LCT维护SAM的parent树)

    点此看题面 大致题意: 给你一个\(01\)串,每次询问前缀编号在一段区间内的两个前缀的最长公共后缀的长度. 离线存储询问 考虑将询问离线,按右端点大小用邻接表存下来(直接排序当然也可以啦). 这样的 ...

  9. LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度 LCT+SAM+线段树

    Code: #include<bits/stdc++.h> #define maxn 200003 using namespace std; void setIO(string s) { ...

随机推荐

  1. 移动端常用单位——rem

    移动端常用单位: ①px:像素大小,固定值 ②%:百分比 ③em(不常用,但是在首行缩进时可以使用):相对自身的font大小(当自身的字体大小也是em做单位时,才会以父元素的字体大小为基准单位) ④r ...

  2. MySQL-SQL基础1

    p.p1 { margin: 0; font: 11px Menlo; background-color: rgba(128, 128, 128, 0.5); min-height: 13px } p ...

  3. Shell脚本基础及基本常用命令

    1.概述 脚本语言(shell.python):解释性语言,用解释器解释 运行效率低 | c.java:描述性语言,运行效率高 以.sh结尾会有高亮显示 执行: sh hello.sh 或者 chmo ...

  4. Linux服务器JDK的安装

    JDK安装 开发java程序必须要的环境 下载JDK rpm. 安装环境 #检测当前系统是否安装Java环境 java -version #如果有就需要卸载 #rpm -qa|grep jdk #检测 ...

  5. noip模拟48

    A. Lighthouse 很明显的容斥题,组合式与上上场 \(t2\) 一模一样 注意判环时长度为 \(n\) 的环是合法的 B. Miner 题意实际上是要求偶拉路 对于一个有多个奇数点的联通块, ...

  6. adb 常用命令大全(6)- 模拟按键输入

    语法格式 input [<source>] <command> [<arg>...] 物理键 # 电源键 adb shell input keyevent 26 # ...

  7. STP(生成树)的概述和工作原理

    一.STP的简介 二.STP的概述 三.STP的工作原理 四.生成树的算法 五.BPDU(桥协议数据单元) 六.STP收敛 TP简介 STP - Spanning Tree Protocol(生成树协 ...

  8. 树莓派的kodi设置遥控器的方法

    首先你需要买一个红外接收器,根据卖家的文档,插到树莓派的GPIO串口上, 我的红外接收器是18入口,17出口, 所以我的config.txt文件设置如下 dtoverlay=lirc-rpi,gpio ...

  9. Django学习day15BBS项目开发4.0(完结)

    每日测验 """ 今日考题: 1.简述自定义标签,过滤器,inclusion_tag的方法,并简要说一说三者的特点及响应流程 2.简述个人侧边栏展示及筛选业务逻辑 3.简 ...

  10. ecshop调用指定分类热销-新品-精品

    在模板页里首页写上代码:         <?php$children = get_children(16);//此处为产品分类ID$smarty->assign( 'bestGoods1 ...