Description

人的一生不仅要靠自我奋斗,还要考虑到历史的行程。

历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势。

你发现在历史的不同时刻,不断的有相同的事情发生。比如,有两个人同时在世纪之交 11 年的时候上台,同样喜欢与洋人谈笑风生,同样提出了以「三」字开头的理论。

你发现,一件事情可以看成是这个 01 串的一个前缀,这个前缀最右边的位置就是这个事情的结束时间。

两件事情的相似度可以看成,这两个前缀的最长公共后缀长度。

现在你很好奇,在一段区间内结束的事情中最相似的两件事情的相似度是多少呢?

Solution

考虑暴力做法,离线询问

因为两个串的最长公共后缀,就是所代表节点的 \(lca\) 的 \(len\)

每一次加入一个前缀,在 \(parent\) 树上往上跳,如果一个点被跳过我们就更新答案

因为右端点固定时,左端点越大,对询问的贡献肯定越多,所以直接覆盖掉这个节点事件的下标(也就是 \(pos\)),所以我们维护这个节点子树内的最大 \(pos\) 值就行了

但是还有一个左端点限制,我们开一个左端点为下标的树状数组维护一下就好了

实际上这个过程就是 \(LCT\) 的 \(access\),那么用 \(LCT\) 做这个过程复杂度就可以均摊为 \(access\) 的复杂度了

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
template<class T>void gi(T &x){
int f;char c;
for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c&15);x*=f;
}
int fa[N],ch[N][2],len[N],cur=1,cnt=1,n,Q,pos[N];
char s[N];int tr[N],ans[N];
struct data{int x,id;};
vector<data>v[N];vector<data>::iterator it;
inline void add(int x,int y){for(int i=x;i>=1;i-=(i&(-i)))tr[i]=max(tr[i],y);}
inline int qry(int x){
int ret=0;
for(int i=x;i<=n;i+=(i&(-i)))ret=max(ret,tr[i]);
return ret;
}
namespace lct{
int fa[N],ch[N][2],w[N],la[N];
inline void mark(int x,int y){w[x]=y;la[x]=y;}
inline bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline void rotate(int x){
int y=fa[x];bool t=ch[y][1]==x;
ch[y][t]=ch[x][!t];fa[ch[y][t]]=y;
ch[x][!t]=y;fa[x]=fa[y];
if(!isrt(y))ch[fa[y]][ch[fa[y]][1]==y]=x;
fa[y]=x;
}
inline void pushdown(int x){
if(!la[x])return ;
mark(ch[x][0],la[x]);mark(ch[x][1],la[x]);la[x]=0;
}
inline void Push(int x){if(!isrt(x))Push(fa[x]);pushdown(x);}
inline void splay(int x){
Push(x);
while(!isrt(x)){
int y=fa[x],p=fa[y];
if(isrt(y))rotate(x);
else if((ch[p][0]==y)==(ch[y][0]==x))rotate(y),rotate(x);
else rotate(x),rotate(x);
}
}
inline void access(int x,int id){
int y=0;
while(x)splay(x),ch[x][1]=y,add(w[x],len[x]),x=fa[y=x];
mark(y,id);
}
}
inline void ins(int c){
int p=cur;cur=++cnt;len[cur]=len[p]+1;
for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur;
if(!p)fa[cur]=1;
else{
int q=ch[p][c];
if(len[p]+1==len[q])fa[cur]=q;
else{
int nt=++cnt;len[nt]=len[p]+1;
memcpy(ch[nt],ch[q],sizeof(ch[q]));
fa[nt]=fa[q];fa[cur]=fa[q]=nt;
for(;p && ch[p][c]==q;p=fa[p])ch[p][c]=nt;
}
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
int x,y;
cin>>n>>Q;
scanf("%s",s+1);
for(int i=1;i<=n;i++)ins(s[i]-'0'),pos[i]=cur;
for(int i=1;i<=Q;i++)gi(x),gi(y),v[y].push_back((data){x,i});
for(int i=2;i<=cnt;i++)lct::fa[i]=fa[i];
for(int i=1;i<=n;i++){
lct::access(pos[i],i);
for(it=v[i].begin();it!=v[i].end();++it)ans[it->id]=qry(it->x);
}
for(int i=1;i<=Q;i++)printf("%d\n",ans[i]);
return 0;
}

LOJ #6041. 事情的相似度的更多相关文章

  1. 【LOJ#6041】事情的相似度(后缀自动机)

    [LOJ#6041]事情的相似度(后缀自动机) 题面 LOJ 题解 \(\mbox{YCB}\)搬了这道题目...\(\mbox{QwQ}\) 还是用到\(lcp\)就是\(parent\)树上的\( ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. #6041. 「雅礼集训 2017 Day7」事情的相似度 [set启发式合并+树状数组扫描线]

    SAM 两个前缀的最长后缀等价于两个点的 \(len_{lca}\) , 题目转化为求 \(l \leq x , y \leq r\) , \(max\{len_{lca(x,y)}\}\) // p ...

随机推荐

  1. Git简单图文教程

    环境: Windows [版本 10.0.15063]64位 Git-2.14.1 64位[下载] TortoiseGit-2.5.0.0 64位[下载],这是一个Git 客户端,外号"乌龟 ...

  2. 数据结构基础——指针及动态内存分配(malloc)

    一.指针 C语言中的指针是一种数据类型,比如说我们用int *a;就定义了一个指针a,它指向一个int类型的数.但是这个指针是未初始化的,所以,一般的,我们都在创建指针时初始化它,以免出错,在还不吃的 ...

  3. 201621123031 《Java程序设计》第4周学习总结

    Week04-面向对象设计与继承 1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 关键词:继承.覆盖.多态.抽象 1.2 尝试使用思维导图将这些关键词组织起来. 1.3 可选: ...

  4. C语言--期末总结

    一. 1.当初你是如何做出选择计算机专业的决定的?经过一个学期,你的看法改变了么,为什么? 你觉得计算机是你喜欢的领域吗,它是你擅长的领域吗? 为什么? 答:当初报志愿的时候,没有具体的想法,只凭借着 ...

  5. Django 个性化管理员站点

    from django.contrib import admin # Register your models here. from .models import Moment class Momen ...

  6. 【iOS】swift-如何理解 if let 与guard?

    著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 作者:黄兢成 链接:http://www.zhihu.com/question/36448325/answer/68614858 ...

  7. crlf注入攻击

    1.crlf 注入攻击. 原理:http数据包通过\r\n\r\n来分开http header何http body 实现:首先这种攻击发生在应用层,且发生在服务器返回给我们的http reponse没 ...

  8. javaScript识别网址文本并转为链接文本

    最近项目有个需求:用户之间发送消息时,如果发送者输入的信息中含有网址文本,要在接受者界面中显示网址链接,点击该链接直接跳转到网页.这个功能和 QQ 发送网址文本的效果非常像,可以说是一模一样的. 思路 ...

  9. Win10安装Ubuntu14.04.5双系统(显示器为DP接口)

    系统安装主要参考了这篇博文Win10+Ubuntu17.04双系统安装,不再重复. 重点说说DP接口的事,如果主机有VGA接口的话可以到此为止了,如果只有DP接口的话可以参考以下内容. 一.Ubunt ...

  10. 创建帧动画1 - xml方式

    废话不多说,先看东西   创建帧动画1 - xml方式 帧动画的创建方式主要以下2种: * 用xml创建动画: * 用代码创建动画:   本文内容主要关注 xml文件 创建帧动画的方式   xml文件 ...