题目传送门

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. Vivado实战—单周期CPU指令分析

    引言   不知道你是否和我有过同样的感受,<计算机组成原理>这门学科学起来如此的艰难:一节课下来,教室黑板上留下了满满的 "足迹",看上去也挺简单的,不就是 0 和 1 ...

  2. CSS样式下border的几种线型

    在用border的时候经常会忘记它有多少种线型以及各种线型的写法:每次都得从头开始,或是用到Google.百度之类的,有空整理了一下 (1)none (没有边框,无论边框宽度设为多大) (2)dott ...

  3. 微信小程序 image 组件 src 请求不能设置 header 的问题

    只能先 wx.downloadFile 得到 tempFilePath,然后设置 src = tempFilePath

  4. MPI集群搭建

    高性能计算     ubantu下集群搭建 参考博客:https://blog.csdn.net/u012304016/article/details/52423738(尊重别人的知识产权),一些细节 ...

  5. MySQL——MySQL安装

    1.rpm yum安装:安装方便.速度快.无法定制 2.二进制安装:解压即可使用,不能定制功能 3.编译安装: 可定制.安装慢: MySQL5.5之前:./configure make make in ...

  6. Walker

      emmm.......随机化.   好吧,我们不熟.   考虑随机选取两组数据高斯消元消除结果后带入检验,能有超过1/2正确就输出.   其实方程就四个,手动解都没问题.   只是要注意看sin与 ...

  7. bean的作用域和生命周期

    一.Bean作用域 二.生命周期 其中,这个类实现各种接口重写各种方法,会按bean的声明周期按序执行: 其中,自定义的初始化和自定义销毁的方法不是实现接口重写,而是成员方法,并且在装配bean即在x ...

  8. 学习Tomcat(二)之容器概览

    Tomcat容器的Server模块有管理容器的启动和关闭.管理了容器内的服务组件Service.管理了全局JNDI资源的功能,对Tomcat容器的生命周期管理有重要意义.Tomcat的服务组件则是To ...

  9. Dockerfile常见命令

    Dockerfile结构 Dockerfile的结构分成了若干部分,每个部分之间的先后顺序有明确的要求: 部分 命令 基础镜像信息 FROM 维护者信息 MAINTAINER 镜像操作指令 RUN.C ...

  10. 关于vue-cli的安装

    (一):*安装 vue-cli 参考: https://cn.vuejs.org/v2/guide/installation.html https://github.com/vuejs/vue-cli ...