【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) { ...
随机推荐
- 你真的认为iphone只是一部手机么
闲言不表,直奔主题.我是一个程序员,上周参加了一个开源软件交流大会,其实会上并没有听到什么新鲜的东西.但是在会中,偶然间听到了一个关于iphone的秘密,却着实令我震惊了,事情具体是这样的,听我慢慢道 ...
- Android开发——你真的了解Dialog、Toast和Snackbar吗
0. 前言 今天给大家带来一篇简单易懂的关于Android提醒小功能的文章.Dialog和Toast我们都不陌生,而Snackbar是Design Support库中提供的新控件,有些朋友可能还不了解 ...
- OpenCV中Mat操作clone() 与copyto()的区别
OpenCV中Mat操作clone() 与copyto()的区别 // Mat is basically a class with two data parts: the matrix header ...
- Airflow使用入门指南
Airflow能做什么 关注公众号, 查看更多 http://mp.weixin.qq.com/s/xPjXMc_6ssHt16J07BC7jA Airflow是一个工作流分配管理系统,通过有向非循环 ...
- python爬虫-爬取盗墓笔记
本来今天要继续更新 scrapy爬取美女图片 系列文章,可是发现使用免费的代理ip都非常不稳定,有时候连接上,有时候连接不上,所以我想找到稳定的代理ip,下次再更新 scrapy爬取美女图片之应对反 ...
- 提取验证码到winform上webbroswer和axwebbroswer
在网上只有webbroswer的代码,所以自己又修改了修改改成axwebbroswer的 public static class yanZhengMaHelp { //webbrowser验证码 pu ...
- sqlite两表更新update
1 2 3 4 5 6 7 8 9 10 11 12 UPDATE t1 SET Column1 = ( SELECT Columnx FROM t2 WHERE t2. KEY = ...
- PHP性能优化 -理论篇
什么情况下,遇到了PHP性能问题? 1 PHP语法使用的不恰当 2 使用PHP语言做不了它不擅长做的事 3 用php语言连接的服务不给力 4 PHP自身的短板 5 我也不 ...
- 华为笔试——C++的int型数字位排序
题目:int型数字位排序 题目介绍:输入int 型整数,按照从右至左的顺序,返回不含重复数字的新整数. 例: 输入: 99824270 输出: 072489 分析:乍一看很简单,但是很容易忽略int ...
- node项目设置环境变量
在UNIX系统中: $ NODE_ENV=production node app 在Windows中: $ set NODE_ENV=production $ node app 这些环境变量会出现在程 ...