【LOJ6041】「雅礼集训 2017 Day7」事情的相似度(用LCT维护SAM的parent树)
大致题意: 给你一个\(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树)的更多相关文章
- 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」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组
题目描述 给你一个长度为 $n$ 的01串,$m$ 次询问,每次询问给出 $l$ .$r$ ,求从 $[l,r]$ 中选出两个不同的前缀的最长公共后缀长度的最大值. $n,m\le 10^5$ 题解 ...
- 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) { ...
随机推荐
- PIE SDK元素事件的监听
1功能简介 元素在操作的过程中,如添加,删除,选中等操作都需要有事件的监听,PIE SDK支持对元素操作事件的监听,下面对元素事件的监听进行介绍. 2功能实现说明 2.1.1 实现思路及原理说明 第一 ...
- Ionic3,懒加载(二)
Ionic懒加载: 普通的ionic项目中,创建好每一个Component页面后,都需要在app.module.ts中进行declaration(声明)后才能进行调用,而这样的声明方式,及在APP加载 ...
- html中的flv视频播放器
项目中要播放flv视屏,第一时间想到html5的<video>标签,只是很可惜<video>兼容性差也就算了,居然还对格式有明确限制,也就是说只支持Ogg.MPEG4.WebM ...
- opensuse13.2国内源和设置命令
ustc-osshttp://mirrors.ustc.edu.cn/opensuse/distribution/13.2/repo/oss/ustc-non-osshttp://mirrors.us ...
- 关于TypeScript中null,undefined的使用
TypeScript本质是javascript,因此基本上js所有的功能在ts上完全可以照搬照抄过来使用.根据ts的文档,有些我觉得值得商榷的——比如null,undefined就是例子. 文档上说一 ...
- C++程序设计基础(2)变量
注:读<程序员面试笔记>笔记总结 1.知识点 (1)C++变量命名只能包含字母.数字.下划线,其中开头不能是数字:大小写敏感:习惯上变量用小写字母,常量.宏定义用大写字母. (2)变量的作 ...
- jQuery autocomplete 应用
1. 引入css和js <link rel="stylesheet" href="{{ url_for('static', filename='jquery.aut ...
- WPF的项目,ListBox 纵向滚动条不显示
最近在做WPF的项目,ListBox 纵向滚动条不显示,但是鼠标滚轮可以在ListBox中使用,但是必须要出现纵向滚动条. 索性就直接在listBox外面包裹一个ScrollViewer. Scro ...
- springboot vue组件写的个人博客系统
个人写的博客管理系统,学习java不到一年 欢迎探讨交流学习 https://github.com/Arsense/ssmBlog 项目地址 如果觉得好的 帮忙star一下 谢谢! 基本技术 环境: ...
- TensorFlow入门:安装常用的依赖模块
TensorFlow运行中常用到一些Python第三方模块: numpy 存储和处理大型矩阵的科学计算包 maplotlib 最著名的绘图库 jupyter scikit-image 图像预处理 li ...