[LOJ6041雅礼集训2017]事情的相似度
题解
\(SAM+set\)启发式合并+扫描线
首先可以发现题目要求的就是查询结尾在一段区间内的\(LCS\)
这个显然就是\(SAM\)的\(parent\)树上的\(step[LCA]\)
我们可以对后缀自动机的每个节点\(u\)开一个\(set\)来维护\(endpos\)集合
然后对\(u\)的儿子的\(right\)集合启发式合并,\(u\)的儿子和\(u\)当前集合内的点的\(LCS\)就是\(step[u]\)
显然在贡献是相同的情况下距离越近的越有效
所以我们对于要合并的点的一个位置\(u\)只需要找这个位置的前驱和后继并加入点对即可
这样我们处理出了若干个\((x,y,v)\)的点对
那么对于一个询问\(l,r\)
有贡献的点对就是\(l\le x , r > y\)
所以我们就把所有的点对和询问按照右端点排序
每扫到一个点对\((x,y,v)\)
就把\(x\)位置加上\(v\)
查询就是查\(l\)位置之前的最大值
代码
#include<set>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 400005 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
char s[M] ;
int n , m , tot ;
int Last , cnt ;
int fa[M] , st[M] , son[M][2] ;
int b[M] , c[M] , ans[M] ;
multiset < int > S[M] ;
struct Q {
int l , r , idx ;
} q[M] ;
struct Node {
int x , y , v ;
Node () { } ;
Node (int Tx , int Ty , int Tv) {
x = Tx , y = Ty , v = Tv ;
if(x > y) swap(x , y) ;
}
} pi[M * 10] ;
inline bool operator < (Q A , Q B) {
return A.r < B.r ;
}
inline bool operator < (Node A , Node B) {
return A.y < B.y ;
}
inline void Insert(int c) {
int np = ++ cnt , p = Last ; Last = np ; st[np] = st[p] + 1 ;
while(p && !son[p][c]) son[p][c] = np , p = fa[p] ;
if(!p) fa[np] = 1 ;
else {
int q = son[p][c] ;
if(st[q] == st[p] + 1) fa[np] = q ;
else {
int nq = ++ cnt ; st[nq] = st[p] + 1 ;
memcpy(son[nq] , son[q] , sizeof(son[q])) ;
fa[nq] = fa[q] ; fa[q] = fa[np] = nq ;
while(p && son[p][c] == q) son[p][c] = nq , p = fa[p] ;
}
}
}
struct BIT {
int c[M] ;
inline int lowbit(int k) { return (k & (-k)) ; }
inline void change(int k , int x) { while(k) c[k] = max(c[k] , x) , k -= lowbit(k) ; }
inline int query(int k) { int ret = 0 ; while(k <= n) ret = max( ret , c[k] ) , k += lowbit(k) ; return ret ; }
} T ;
inline void Solve() {
int lst = 1 ;
for(int i = 1 ; i <= m ; i ++) {
for(int j = lst ; j <= tot ; j ++) {
if(q[i].r >= pi[j].y) {
T.change(pi[j].x , pi[j].v) ;
lst = j + 1 ;
}
else break ;
}
ans[q[i].idx] = T.query(q[i].l) ;
}
}
int main() {
n = read() ; m = read() ;
scanf("%s",s + 1) ; Last = cnt = 1 ;
for(int i = 1 ; i <= n ; i ++) {
Insert(s[i] - '0') ;
S[Last].insert(i) ;
}
for(int i = 1 ; i <= cnt ; i ++) ++ c[st[i]] ;
for(int i = 1 ; i <= n ; i ++) c[i] += c[i - 1] ;
for(int i = cnt ; i >= 1 ; i --) b[c[st[i]] --] = i ;
for(int i = cnt , p ; i >= 1 ; i --) {
p = b[i] ;
if(!fa[p]) continue ;
if(S[fa[p]].size() < S[p].size())
swap(S[fa[p]] , S[p]) ;
set < int >::iterator it , nw , pre , nxt ;
for(it = S[p].begin() ; it != S[p].end() ; ++it) {
S[fa[p]].insert(*it) ;
nw = pre = nxt = S[fa[p]].find(*it) ; ++ nxt ;
if(pre != S[fa[p]].begin()) -- pre , pi[++tot] = Node (*pre , *nw , st[fa[p]]) ;
if(nxt != S[fa[p]].end()) pi[++tot] = Node (*nw , *nxt , st[fa[p]]) ;
S[fa[p]].erase(*it) ;
}
for(it = S[p].begin() ; it != S[p].end() ; ++it)
S[fa[p]].insert(*it) ;
}
for(int i = 1 ; i <= m ; i ++)
q[i].idx = i , q[i].l = read() , q[i].r = read() ;
sort(q + 1 , q + m + 1) ;
sort(pi + 1 , pi + tot + 1) ;
Solve() ;
for(int i = 1 ; i <= m ; i ++)
printf("%d\n",ans[i]) ;
return 0 ;
}
[LOJ6041雅礼集训2017]事情的相似度的更多相关文章
- 「雅礼集训 2017 Day7」事情的相似度
「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...
- LOJ_6045_「雅礼集训 2017 Day8」价 _最小割
LOJ_6045_「雅礼集训 2017 Day8」价 _最小割 描述: 有$n$种减肥药,$n$种药材,每种减肥药有一些对应的药材和一个收益. 假设选择吃下$K$种减肥药,那么需要这$K$种减肥药包含 ...
- 「雅礼集训 2017 Day2」解题报告
「雅礼集训 2017 Day2」水箱 我怎么知道这种题目都能构造树形结构. 根据高度构造一棵树,在树上倍增找到最大的小于约束条件高度的隔板,开一个 \(vector\) 记录一下,然后对于每个 \(v ...
- 「雅礼集训 2017 Day1」 解题报告
「雅礼集训 2017 Day1」市场 挺神仙的一题.涉及区间加.区间除.区间最小值和区间和.虽然标算就是暴力,但是复杂度是有保证的. 我们知道如果线段树上的一个结点,\(max=min\) 或者 \( ...
- [LOJ 6031]「雅礼集训 2017 Day1」字符串
[LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...
- [LOJ 6030]「雅礼集训 2017 Day1」矩阵
[LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...
- [LOJ 6029]「雅礼集训 2017 Day1」市场
[LOJ 6029] 「雅礼集训 2017 Day1」市场 题意 给定一个长度为 \(n\) 的数列(从 \(0\) 开始标号), 要求执行 \(q\) 次操作, 每次操作为如下四种操作之一: 1 l ...
- 【LYOI 212】「雅礼集训 2017 Day8」价(二分匹配+最大权闭合子图)
「雅礼集训 2017 Day8」价 内存限制: 512 MiB时间限制: 1000 ms 输入文件: z.in输出文件: z.out [分析] 蛤?一开始看错题了,但是也没有改,因为不会做. 一开 ...
- loj #6046. 「雅礼集训 2017 Day8」爷
#6046. 「雅礼集训 2017 Day8」爷 题目描述 如果你对山口丁和 G&P 没有兴趣,可以无视题目背景,因为你估计看不懂 …… 在第 63 回战车道全国高中生大赛中,军神西住美穗带领 ...
随机推荐
- 李洪强iOS开发之 - enum与typedef enum的用法
李洪强iOS开发之 - enum与typedef enum的用法 01 - 定义枚举类型 上面我们就在ViewController.h定义了一个枚举类型,枚举类型的值默认是连续的自然数,例如例子中的T ...
- 【健康生活】Google、百度之间的选择
没有什么技术性的分析,仅仅是个人吐槽而已. 一般人遇到问题就会说一句"百度一下",说实话,百度在中国推广的真的非常不错,可谓是家喻户晓,搜索个八卦新闻,小文章,小电影什么的的确非常 ...
- HDU 6040 Hints of sd0061 nth_element函数
Hints of sd0061 Problem Description sd0061, the legend of Beihang University ACM-ICPC Team, retired ...
- VS 预先生成事件命令
宏 说明 $(ConfigurationName) 当前项目配置的名称(例如,“Debug|Any CPU”). $(OutDir) 输出文件目录的路径,相对于项目目录.这解析为“输出目录”属性的值. ...
- Linux Linker
文章原文:http://zhidao.baidu.com/link?url=U2Mtcc6BKi4vuQ1MO8U6s9gNm4y9Epphz03veA2lVpRWMozyVdj0PYvw1ZU9qj ...
- Android 单击跳转到打电话发短信界面,长按打电话发短信
<uses-permission android:name="android.permission.CALL_PHONE"/><uses-permission a ...
- Mac OS X 开发环境搭建之利用 Parallel Desktop 安装 CentOS 7 [转载]
背景 在企业级软件系统中,数据库的地位是比较高的,而且一般都要求支持多种数据库,如 Oracle. DB2.MySQL 等,它们的最新版本大多都不再支持 Mac OS X 系统,所以装一个 Linux ...
- 牛客练习赛42 E.热爆了
这可能是全场最长的一份代码 问的其实是对于关键点的斯坦纳树大小 考虑补集转化,不合法的点就是它的子树中没有关键点的点和斯坦纳树根的祖先 树根不难求,关键点中dfs序最大最小点的LCA就是了 问题在前者 ...
- 织梦DEDE多选项筛选_联动筛选功能的实现_二次开发
织梦默认的列表页没有筛选功能,但有时候我们做产品列表页的时候,产品的字段比较多,很多人都需要用到筛选功能,这样可以让用户更方便的找到自己所需要的东西,实现这个联动筛选功能需要对织梦进行二次开发,下面就 ...
- 异常、Throwable、finally、File类(十九)
1.异常的概述和分类 * A:异常的概述 * 异常就是Java程序在运行过程中出现的错误.* B:异常的分类 * 通过API查看Throwable * Error * 服务器宕机,数据库崩溃等 * E ...