点此看题面

大致题意: 给你一个\(01\)串,每次询问前缀编号在一段区间内的两个前缀的最长公共后缀的长度。

离线存储询问

考虑将询问离线,按右端点大小用邻接表存下来(直接排序当然也可以啦)。

这样的好处是什么呢?

我们就可以对于每一个枚举到的右端点来对答案进行更新,然后再处理对应询问。

则对于当前一个已确定的右端点\(r\),显然询问\([l,r]\)的答案就是两个编号均大于等于\(l\)的点的答案的最大值(注意无须考虑右边界),而这可以直接拿线段树或树状数组统计。

由此可以发现,这样一来最大的好处就在于,不需要删除某种情况下的答案,而是可以直接叠加统计。

这样一来就可做了许多。

后缀自动机:题意转化

首先,这道题看起来很像\(SAM\)

所以,我们先无脑打个板子,建一个后缀自动机。

然后来考虑一下性质。

首先我们要知道,对于两个前缀,它们的最长公共后缀长度,就相当于在\(parent\)树上这两个点的\(LCA\)的\(Len\)

那么,问题似乎就转换成了求\(parent\)树上一个点集内任意两点的\(LCA\)的\(Len\)的最大值

然后就可以大力数据结构硬搞了。

\(LCT\)维护\(parent\)树

考虑之前提到过的离线,则我们只需考虑每次加入一个新的节点对答案造成的影响。

结合题意转化,则其实也就相当于要求新加入的这个点与之前所有点的\(LCA\)的\(Len\)。

注意\(LCA\),便可以想到\(LCT\)中的一个技巧:\(Access\)求\(LCA\)。(关于这个技巧,有一道挺好的例题:【BZOJ4573】[ZJOI2016] 大森林

因此,修改只要在\(Access\)的过程中进行即可。

然后考虑如果一个点被作为新加入点与之前多个点的\(LCA\),则显然应该选择较后出现的进行单点修改(因为询问时我们区间询问某个位置到当前右端点间的最大值,则显然较后出现的可以影响到较先出现的答案)。

则我们可以记录一个\(V\),每次\(Access\)后把根所在的\(Splay\)内所有节点(即树中\(LCA(now,pre)\)到根节点的路径上的所有节点)的\(V\)改为新加入节点的编号。

具体实现详见代码。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define Gmax(x,y) (x<(y)&&(x=(y)))
#define swap(x,y) (x^=y^=x^=y)
#define pb(x,y) (nxt[y]=lnk[x],lnk[x]=y)
using namespace std;
int n,m,a[N+5],q[N+5],lnk[N+5],nxt[N+5],ans[N+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
I void readbit(int& x) {W(!D);x=c&1;}
I void clear() {fwrite(FO,1,C,stdout),C=0;}
}F;
template<int SZ> class SuffixAutomation//后缀自动机
{
private:
int lst;struct Trie {int L,F,S[2];}O[SZ<<1];
public:
int tot,l[SZ<<1],f[SZ<<1];I SuffixAutomation() {tot=lst=1;}
I void Record() {for(RI i=1;i<=tot;++i) l[i]=O[i].L,f[i]=O[i].F;}
I int Insert(CI x)//插入节点
{
RI p=lst,q,k,now=lst=++tot;O[now].L=O[p].L+1;
W(p&&!O[p].S[x]) O[p].S[x]=now,p=O[p].F;if(!p) return O[now].F=1,now;
if(O[p].L+1==O[q=O[p].S[x]].L) return O[now].F=q,now;
O[k=++tot]=O[q],O[k].L=O[p].L+1,O[now].F=O[q].F=k;
W(p&&!(O[p].S[x]^q)) O[p].S[x]=k,p=O[p].F;return now;
}
};
template<int SZ> class TreeArray//树状数组
{
private:
#define lowbit(x) ((x)&-(x))
int a[SZ+5];
public:
I void Add(RI x,CI v) {W(x) Gmax(a[x],v),x-=lowbit(x);}//单点修改
I int Qry(RI x) {RI t=0;W(x<=n) Gmax(t,a[x]),x+=lowbit(x);return t;}//区间询问
};
class LinkCutTree//LCT
{
private:
#define Upt(x,v) (O[x].f=O[x].V=v)
#define PD(x) (O[x].f&&(Upt(O[x].S[0],O[x].f),Upt(O[x].S[1],O[x].f),O[x].f=0))
#define IR(x) (O[O[x].F].S[0]^x&&O[O[x].F].S[1]^x)
#define Wh(x) (O[O[x].F].S[1]==x)
#define Co(x,y,d) (O[O[x].F=y].S[d]=x)
static Con int SZ=N<<1;int p[SZ+5],St[SZ+5];struct node {int f,V,F,S[2];}O[SZ+5];
SuffixAutomation<N> SAM;TreeArray<N<<1> T;
I void Ro(CI x)
{
RI f=O[x].F,p=O[f].F,d=Wh(x);!IR(f)&&(O[p].S[Wh(f)]=x);
O[x].F=p,Co(O[x].S[d^1],f,d),Co(f,x,d^1);
}
I void S(CI x)
{
RI f=x,T=0;W(St[++T]=f,!IR(f)) f=O[f].F;W(T) PD(St[T]),--T;
W(!IR(x)) f=O[x].F,!IR(f)&&(Ro(Wh(x)^Wh(f)?x:f),0),Ro(x);
}
public:
I void Init(CI x,int* v)
{
RI i;for(i=1;i<=n;++i) p[i]=SAM.Insert(v[i]);SAM.Record();
for(i=1;i<=SAM.tot;++i) O[i].F=SAM.f[i];
}
I void Ac(RI x,CI v)//Access求LCA的过程,注意更新节点信息与答案
{
RI s;for(x=p[x],s=0;x;x=O[s=x].F) S(x),
T.Add(O[x].V,SAM.l[x]),O[x].S[1]=s;Upt(s,v);
}
I int Query(CI x) {return T.Qry(x);}//询问答案
}LCT;
int main()
{
RI Qtot,i,j,x;for(F.read(n,Qtot),i=1;i<=n;++i) F.readbit(a[i]);
for(LCT.Init(n,a),i=1;i<=Qtot;++i) F.read(q[i],x),pb(x,i);//离线用邻接表存储
for(i=1;i<=n;++i) for(LCT.Ac(i,i),j=lnk[i];j;j=nxt[j]) ans[j]=LCT.Query(q[j]);//枚举右端点,更新信息并处理询问
for(i=1;i<=Qtot;++i) F.writeln(ans[i]);return F.clear(),0;//输出答案
}

【LOJ6041】「雅礼集训 2017 Day7」事情的相似度(用LCT维护SAM的parent树)的更多相关文章

  1. LOJ6041. 「雅礼集训 2017 Day7」事情的相似度 [后缀树,LCT]

    LOJ 思路 建出反串的后缀树,发现询问就是问一个区间的点的\(lca\)的深度最大值. 一种做法是dfs的时候从下往上合并\(endpos\)集合,发现插入一个点的时候只需要把与前驱后继的贡献算进去 ...

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

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

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

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

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

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

  5. 【loj6041】「雅礼集训 2017 Day7」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组

    题目描述 给你一个长度为 $n$ 的01串,$m$ 次询问,每次询问给出 $l$ .$r$ ,求从 $[l,r]$ 中选出两个不同的前缀的最长公共后缀长度的最大值. $n,m\le 10^5$ 题解 ...

  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. loj#6041. 「雅礼集训 2017 Day7」事情的相似度(后缀自动机+启发式合并)

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

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

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

随机推荐

  1. PIE SDK元素事件的监听

    1功能简介 元素在操作的过程中,如添加,删除,选中等操作都需要有事件的监听,PIE SDK支持对元素操作事件的监听,下面对元素事件的监听进行介绍. 2功能实现说明 2.1.1 实现思路及原理说明 第一 ...

  2. Ionic3,懒加载(二)

    Ionic懒加载: 普通的ionic项目中,创建好每一个Component页面后,都需要在app.module.ts中进行declaration(声明)后才能进行调用,而这样的声明方式,及在APP加载 ...

  3. html中的flv视频播放器

    项目中要播放flv视屏,第一时间想到html5的<video>标签,只是很可惜<video>兼容性差也就算了,居然还对格式有明确限制,也就是说只支持Ogg.MPEG4.WebM ...

  4. opensuse13.2国内源和设置命令

    ustc-osshttp://mirrors.ustc.edu.cn/opensuse/distribution/13.2/repo/oss/ustc-non-osshttp://mirrors.us ...

  5. 关于TypeScript中null,undefined的使用

    TypeScript本质是javascript,因此基本上js所有的功能在ts上完全可以照搬照抄过来使用.根据ts的文档,有些我觉得值得商榷的——比如null,undefined就是例子. 文档上说一 ...

  6. C++程序设计基础(2)变量

    注:读<程序员面试笔记>笔记总结 1.知识点 (1)C++变量命名只能包含字母.数字.下划线,其中开头不能是数字:大小写敏感:习惯上变量用小写字母,常量.宏定义用大写字母. (2)变量的作 ...

  7. jQuery autocomplete 应用

    1. 引入css和js <link rel="stylesheet" href="{{ url_for('static', filename='jquery.aut ...

  8. WPF的项目,ListBox 纵向滚动条不显示

    最近在做WPF的项目,ListBox 纵向滚动条不显示,但是鼠标滚轮可以在ListBox中使用,但是必须要出现纵向滚动条.  索性就直接在listBox外面包裹一个ScrollViewer. Scro ...

  9. springboot vue组件写的个人博客系统

    个人写的博客管理系统,学习java不到一年 欢迎探讨交流学习 https://github.com/Arsense/ssmBlog  项目地址 如果觉得好的 帮忙star一下 谢谢! 基本技术 环境: ...

  10. TensorFlow入门:安装常用的依赖模块

    TensorFlow运行中常用到一些Python第三方模块: numpy 存储和处理大型矩阵的科学计算包 maplotlib 最著名的绘图库 jupyter scikit-image 图像预处理 li ...