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

题目链接

我们先将字符串建后缀自动机。然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点的\(lca\)的\(maxlen\)。

所以现在问题就变成了一个树上问题:给定一棵树,每个点有一个权值\((mxlen)\),询问编号在一段区间内的点两两之间\(lca\)权值的最大值。

方法很多,这里用的\(dsu\ on\ tree\)。对于每个点\(v\),我们计算其作为\(lca\)的贡献。显然贡献的情况是一个点对,他们在\(v\)的不同子树中(\(v\)自己也算一个子树)。但是这样点对的数量可能达到\(O(n^2)\)。

不过我们仔细思考一下就会发现,其实这样的点对不多。对于一个\(lca\),一个子节点\(v\),我们要与一个在之前已经加入的节点,我们发现,根据贪心,只需要与\(v\)的前驱和后继组合就可以了。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 200005 using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} int n,m;
char s[N];
int ch[N<<1][2],fail[N<<1],mxlen[N<<1];
int id[N<<1];
int cnt=1,last=1; void Insert(int f,int i) {
static int now,p;
now=++cnt;
p=last,last=now;
id[now]=i;
mxlen[now]=mxlen[p]+1;
while(p&&!ch[p][f]) ch[p][f]=now,p=fail[p];
if(!p) return fail[now]=1,void(); int q=ch[p][f];
if(mxlen[q]==mxlen[p]+1) return fail[now]=q,void(); int New=++cnt;
memcpy(ch[New],ch[q],sizeof(ch[q]));
fail[New]=fail[q];
fail[q]=fail[now]=New;
mxlen[New]=mxlen[p]+1;
while(p&&ch[p][f]==q) ch[p][f]=New,p=fail[p];
} struct load {int to,next;}e[N<<2];
int h[N<<1],edge=1;
void add(int i,int j) {e[++edge]=(load) {j,h[i]};h[i]=edge;}
int val[N<<1]; int size[N<<1],son[N<<1];
void dfs(int v) {
size[v]=1;
for(int i=h[v];i;i=e[i].next) {
int to=e[i].to;
dfs(to);
size[v]+=size[to];
if(size[son[v]]<size[to]) son[v]=to;
}
} set<int>pos;
set<int>::iterator it;
void statis(int v,int flag) {
if(id[v]) {
if(flag) pos.insert(id[v]);
else pos.erase(id[v]);
}
for(int i=h[v];i;i=e[i].next) {
int to=e[i].to;
statis(to,flag);
}
} struct node {
int l,r,mx;
bool operator <(const node &a)const {return r<a.r;}
}st[N*50];
int sum;
struct query {
int l,r,id;
bool operator <(const query &a)const {return r<a.r;}
}q[N];
int ans[N]; void cal(int v,int mx) {
if(id[v]) {
it=pos.lower_bound(id[v]);
if(it!=pos.end()) st[++sum]=(node) {id[v],*it,mx};
if(it!=pos.begin()) st[++sum]=(node) {*(--it),id[v],mx};
}
for(int i=h[v];i;i=e[i].next) {
int to=e[i].to;
cal(to,mx);
}
} void solve(int v,int flag) {
for(int i=h[v];i;i=e[i].next) {
int to=e[i].to;
if(to==son[v]) continue ;
solve(to,0);
}
if(son[v]) solve(son[v],1);
if(id[v]) {
it=pos.lower_bound(id[v]);
if(it!=pos.end()) st[++sum]=(node) {id[v],*it,val[v]};
if(it!=pos.begin()) st[++sum]=(node) {*(--it),id[v],val[v]};
pos.insert(id[v]);
}
for(int i=h[v];i;i=e[i].next) {
int to=e[i].to;
if(to==son[v]) continue ;
cal(to,val[v]);
statis(to,1);
}
if(!flag) pos.clear();
} void solve2(int v) {
if(id[v]) pos.insert(id[v]);
for(int i=h[v];i;i=e[i].next) {
int to=e[i].to;
solve2(to);
}
for(int i=h[v];i;i=e[i].next) {
int to=e[i].to;
cal(to,val[v]);
statis(to,1);
}
pos.clear();
}
struct Bit {
int tem[N];
int low(int i) {return i&(-i);}
void add(int v,int f) {for(int i=v;i<=n;i+=low(i)) tem[i]=max(tem[i],f);}
int query(int v) {
int ans=0;
for(int i=v;i;i-=low(i)) ans=max(ans,tem[i]);
return ans;
}
}bit; int main() {
n=Get(),m=Get();
scanf("%s",s+1);
for(int i=1;i<=n;i++) Insert(s[i]-'0',i);
for(int i=2;i<=cnt;i++) {
val[i]=mxlen[i];
add(fail[i],i);
}
dfs(1);
solve(1,1);
sort(st+1,st+1+sum); for(int i=1;i<=m;i++) q[i].l=Get(),q[i].r=Get(),q[i].id=i;
sort(q+1,q+1+m); int tag=1;
for(int i=1;i<=m;i++) {
while(tag<=sum&&st[tag].r<=q[i].r) {
bit.add(n-st[tag].l+1,st[tag].mx);
tag++;
}
ans[q[i].id]=bit.query(n-q[i].l+1);
} for(int i=1;i<=m;i++) cout<<ans[i]<<"\n";
return 0;
}

「雅礼集训 2017 Day7」事情的相似度的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. 【LOJ6041】「雅礼集训 2017 Day7」事情的相似度(用LCT维护SAM的parent树)

    点此看题面 大致题意: 给你一个\(01\)串,每次询问前缀编号在一段区间内的两个前缀的最长公共后缀的长度. 离线存储询问 考虑将询问离线,按右端点大小用邻接表存下来(直接排序当然也可以啦). 这样的 ...

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

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

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

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

随机推荐

  1. 4款开源免费的数据可视化JavaScript库

    概述:交互式数据可视化在很大程度上取决于JavaScript库的任务能力.在这篇文章中,我们将看看四个JavaScript库:D3,InfoVis,Processing.js,和Recline.js. ...

  2. Java字符串String

    Java字符串String 我们知道Java的字符窜是Immutable(不可变)的,一旦创建就不能更改其内容了:平常我们对字符串的操作是最多的,其实对字符串的操作,返回的字符串都是新建的字符串对象, ...

  3. java中int和Integer比较大小

    Integer是int的封装对象,两个对象==比较的是栈的值 Integer a = new Integer(1); Integer b = new Integer(1); a与b存的是Integer ...

  4. JS的分号可以省掉吗?

    摘要: JavaScript语言从设计之初就是考虑带分号的,使用不带分号的编码规则就要小心点啦. 背景 最近在项目中开始使用新的编码规范,一开始ESLint报一大堆错误,改得我想砸键盘,花了好些时间才 ...

  5. Python 练习: 计算器

    import re def format_string(s): # 对表达式进行格式化 s = s.replace(' ', '') s = s.replace("--", &qu ...

  6. layui 图片上传+表单提交+ Spring MVC

    Layui 的上传是最常用的, 不可或缺, 记录一下代码, 以后复制都能用!! 1.前端HTML: <div class="layui-form-item"> < ...

  7. 小结:ES7——async和await初识

    一.async async其实是ES7才有有的关键字,async的意思是异步,顾名思义是有关异步的操作 async用于声明一个函数是异步的. 通常情况下async.await都是跟随promise一起 ...

  8. 【读书笔记】iOS-storyBoard-为一个按钮添加一个点击事件

    按照故事板的用语,应用中的一个界面屏幕被称作一个”场景(Scene)",以后添加额外的场景时,停靠区中将有另一个部分. 一,新建立一个工程,如图所示. 二,选中Main.storyboard ...

  9. 关于Bootstrap fileinput 上传新文件,移除时触发服务器同步删除的配置

    在Bootstrap fileinput中移除预览文件时可以通过配置initialPreviewConfig: [ { url:'deletefile',key:fileid } ] 来同步删除服务器 ...

  10. 《Inside C#》笔记(八) 接口

    接口可以认为是属于不同继承树的代码之间的行为约定.C#的接口相当于是一种特殊的抽象类,这种抽象类的内部只有虚方法. 一 接口的使用 a) 接口内部可以包含方法.属性.索引器和事件,这些成员都不在接口中 ...