点此看题面

大致题意: 给你一个\(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. oracle12C--DG FAR SYNC 部署(前提为搭建好12C的DG)

    <<往期12CDG搭建>> 一,理解同步异步模式 01, 使用LGWR 进程的SYNC 方式 1)Primary Database 产生的Redo 日志要同时写到日志文件和网络 ...

  2. setContentView和inflate区别

    一般用LayoutInflater做一件事:inflate inflate这个方法总共有四种形式(见下面),目的都是把xml表述的layout转化为View对象.其中有一个比较常用,View infl ...

  3. Mysql系列-字符集

    字符集 怎样选择合适的字符集 如果应用程序需要发布到很多国家和地区,需要支持各种各样的文字,则选择Unicode编码,Mysql中即UTF-8.q如果需要将数据导入数据库,这时候要注意数据库字符集对数 ...

  4. 迪米特法則 Law of Demeter

    又稱為"最小知識"原則, 若對Law of Demeter做一個簡單總結: 任何對象的任何方法只能調用以下對象中的方法: (1) 該對象本身 (2) 所傳入的參數對象 (3) 它所 ...

  5. 如何给MySql创建连接用户并授权

    一般在为MySql创建用户时建议使用GRANT前台命令,当然如果对我们开发者而言,方法还有很多种,比如使用INSERT命令,甚至是直接修改mysql user数据表,但仍然建议按照MySQL规范去授权 ...

  6. 121、Django rest framework入门使用

    框架介绍 为你的django平台通过model生成对应的restfull api,并可以通过对应的http接口来进行 post .get.put.delete等操作.本文是也并非入门级别,不会带你去了 ...

  7. awk - Unix, Linux Command---reference

    http://www.tutorialspoint.com/unix_commands/awk.htm NAME gawk - pattern scanning and processing lang ...

  8. [转]Oracle job procedure 存储过程定时任务

    本文转自:http://www.cnblogs.com/hoojo/p/oracle_procedure_job_interval.html oracle job有定时执行的功能,可以在指定的时间点或 ...

  9. UML建模—EA的使用起步

    Enterprise Architect(EA) 是一个功能比较强悍的建模工具. 对于一个软件设计者来说,从需求分析到业务设计.类模型设计.数据库设计到测试.发布.部署等一系列软件设计必须的操作都可以 ...

  10. C#异步编程模型

    什么是异步编程模型 异步编程模型(Asynchronous Programming Model,简称APM)是C#1.1支持的一种实现异步操作的编程模型,虽然已经比较“古老”了,但是依然可以学习一下的 ...