【loj6041】「雅礼集训 2017 Day7」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组
给你一个长度为 $n$ 的01串,$m$ 次询问,每次询问给出 $l$ 、$r$ ,求从 $[l,r]$ 中选出两个不同的前缀的最长公共后缀长度的最大值。
$n,m\le 10^5$
题解
后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组
两个前缀的最长公共后缀,在正串后缀自动机上体现为pre树上两点LCA的深度。
考虑统计pre树上一个点的贡献:对于两个前缀 $x$ 、$y$ ,它能够影响的询问左端点小于等于 $x$ ,右端点大于等于 $y$ 。因此影响最大化的前缀对就是排序后相邻的两个,每次只需要考虑这些前缀对。
那么我们考虑两个子树合并的过程,使用STL-set维护前驱后继成为贡献。这个过程可以启发式合并,把小的合并到大的中。
剩下的就是对于询问 $[l,r]$ ,询问前缀对中第一个 $\ge l$ ,第二个 $\le r$ 的最大值。离线+扫描线+树状数组维护前缀最小值即可。
时间复杂度瓶颈在于启发式合并STL-set,为 $O(n\log^2n)$ 。
#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
using namespace std;
struct data
{
int x , y , z;
data() {}
data(int a , int b , int c) {x = a , y = b , z = c;}
bool operator<(const data &a)const {return x < a.x;}
}a[N * 20] , q[N];
set<int> s[N];
int pre[N] , c[N][2] , dis[N] , val[N] , last = 1 , tot = 1 , head[N] , to[N] , next[N] , cnt , bl[N] , ta , f[N] , n , ans[N];
char str[N];
void insert(int k , int ch)
{
int p = last , np = last = ++tot;
dis[np] = dis[p] + 1 , s[np].insert(k);
while(p && !c[p][ch]) c[p][ch] = np , p = pre[p];
if(!p) pre[np] = 1;
else
{
int q = c[p][ch];
if(dis[q] == dis[p] + 1) pre[np] = q;
else
{
int nq = ++tot;
memcpy(c[nq] , c[q] , sizeof(c[q]));
dis[nq] = dis[p] + 1 , pre[nq] = pre[q] , pre[np] = pre[q] = nq;
while(p && c[p][ch] == q) c[p][ch] = nq , p = pre[p];
}
}
}
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x)
{
int i;
set<int>::iterator j , k;
for(i = head[x] ; i ; i = next[i])
{
dfs(to[i]);
if(s[bl[x]].size() > s[bl[to[i]]].size())
{
for(j = s[bl[to[i]]].begin() ; j != s[bl[to[i]]].end() ; j ++ )
{
k = s[bl[x]].upper_bound(*j);
if(k != s[bl[x]].end()) a[++ta] = data(*j , *k , dis[x]);
if(k != s[bl[x]].begin()) a[++ta] = data(*--k , *j , dis[x]);
s[bl[x]].insert(*j);
}
}
else
{
for(j = s[bl[x]].begin() ; j != s[bl[x]].end() ; j ++ )
{
k = s[bl[to[i]]].upper_bound(*j);
if(k != s[bl[to[i]]].end()) a[++ta] = data(*j , *k , dis[x]);
if(k != s[bl[to[i]]].begin()) a[++ta] = data(*--k , *j , dis[x]);
s[bl[to[i]]].insert(*j);
}
bl[x] = bl[to[i]];
}
}
}
inline void fix(int x , int a)
{
int i;
for(i = x ; i <= n ; i += i & -i) f[i] = max(f[i] , a);
}
inline int query(int x)
{
int i , ans = 0;
for(i = x ; i ; i -= i & -i) ans = max(ans , f[i]);
return ans;
}
int main()
{
int m , i , p;
scanf("%d%d%s" , &n , &m , str + 1);
for(i = 1 ; i <= n ; i ++ ) insert(i , str[i] - '0');
for(i = 2 ; i <= tot ; i ++ ) add(pre[i] , i);
for(i = 1 ; i <= tot ; i ++ ) bl[i] = i;
dfs(1);
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &q[i].x , &q[i].y) , q[i].z = i;
sort(a + 1 , a + ta + 1) , sort(q + 1 , q + m + 1);
for(p = ta , i = m ; i ; i -- )
{
while(p && a[p].x >= q[i].x) fix(a[p].y , a[p].z) , p -- ;
ans[q[i].z] = query(q[i].y);
}
for(i = 1 ; i <= m ; i ++ ) printf("%d\n" , ans[i]);
return 0;
}
【loj6041】「雅礼集训 2017 Day7」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组的更多相关文章
- LOJ6041. 「雅礼集训 2017 Day7」事情的相似度 [后缀树,LCT]
LOJ 思路 建出反串的后缀树,发现询问就是问一个区间的点的\(lca\)的深度最大值. 一种做法是dfs的时候从下往上合并\(endpos\)集合,发现插入一个点的时候只需要把与前驱后继的贡献算进去 ...
- 「雅礼集训 2017 Day7」事情的相似度
「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...
- 【LOJ 6041】「雅礼集训 2017 Day7」事情的相似度
Description 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的 ...
- 【刷题】LOJ 6041 「雅礼集训 2017 Day7」事情的相似度
题目描述 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的有相同的事情发 ...
- 【LOJ6041】「雅礼集训 2017 Day7」事情的相似度(用LCT维护SAM的parent树)
点此看题面 大致题意: 给你一个\(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) { ...
随机推荐
- 【MYSQL命令】mysql基础命令
1.查询MYSQL当前用户命令:select user() mysql> select user(); +------------------------+ | user() | +------ ...
- jenkins统计单元测试的覆盖率
前提:单元测试和被测代码在一个仓库 maven的pom配置 依赖增加 <dependency> <groupId>org.jacoco</groupId> < ...
- Spring学习(三)-----Spring自动装配Beans
在Spring框架,可以用 auto-wiring 功能会自动装配Bean.要启用它,只需要在 <bean>定义“autowire”属性. <bean id="custom ...
- XAF-属性编辑器中的EditMask,DisplayFormat格式化字符串该如何设置
XAF项目中有个DisplayFormat和EditMask设置,其中: 任何地方看到的DisplayFormat都是用于显示时,即非修改状态的编辑器,显示值的格式. EditMask是指编辑时的格式 ...
- activeX 打包
原文 http://www.docin.com/p-409284488.html CAB打包文档说明 文档目的 本文档的目的在于说明将ocx和dll以及相关的文件打包成一个CAB包,以便在网页下调用o ...
- 同一个电脑配置两个Git问题
拿到公司电脑后,正常配置gitlab,以及设置邮箱等等,可以使用公司邮箱,以及一系列设置 git config --global user.name "userName" git ...
- Python中的内建函数(Built_in Funtions)
前言 在Python官方文档的标准库章节中,第一节是简介,第二节就是Built_in Functions,可见内建函数是Python标准库的重要组成部分,而有很多内建函数我们平时却很少用到或根本就不知 ...
- 运输层(TCP/UDP)详解
TCP和UDP的区别: tcp是面向连接的可靠的传输协议 udp是非连接的不可靠的传输协议 TCP组成 可以看到虽然tcp是面向字节流的,但是其传输的基本单位还是报文(tcp首部和数据,ip报文和ud ...
- idea 模版之自定义类与方法注释
idea 模版之自定义类与方法注释 很多公司都有要求的代码注释规范,我们每新建类或者方法的时候从新复制粘贴很麻烦,而且容易粘错. 当然自定义模板还可以用到很多地方,比如系统自带的 sout就是syst ...
- Dubbo背景和简介
转载出处 Dubbo开始于电商系统,因此在这里先从电商系统的演变讲起. 单一应用框架(ORM) 当网站流量很小时,只需一个应用,将所有功能如下单支付等都部署在一起,以减少部署节点和成本. 缺点:单一的 ...