LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度 LCT+SAM+线段树
我们有一个经典模型:
两个串的最长公共后缀长度,是后缀树中两点 LCA 的深度.
直接求 LCA 似乎有些困难,不妨这样想 :
设两个串在后缀树中对应的点分别为 $a,b$,将 $a$ 到根的路径涂色,$b$ 向根爬,遇到的第一个涂色点即为 $a$ 与 $b$ 的 LCA.
我们用 $LCT$ 来维护 这颗树,涂色操作直接 $Access$ 并区间赋值.
此时树的形态是怎样的 ?
$a$ 点到根的路径是一个重链,$b$ 向上爬肯定会爬到 $a$ 所在的重链上.
直接爬肯定会很慢,不妨直接 $Access(b)$ ?
考虑 $Access$ 时的语句 : $y=x,x=f_{x}$.
我们在 $Access(b)$ 过程中碰到的第一个被涂色的点其实就是我们要求的 LCA.
尤其当被涂色的点变多的时候,每次 $Access$ 的复杂度就是均摊 $log_{2}{n}$ 的了.
是不是十分神奇 ?
观察这部分代码:
void Access(int x,int co)
{
int t=0;
while(x)
{
splay(x);
if(pos[x]) tr::update(1,n,1,pos[x],dis[x]);
pos[x]=co, rson=t, t=x,x=f[x];
}
}
我们一边 $Access$ ,一边将该询问点向上爬,每次遇到一个新的重链就将重链染成当前颜色(区间中的下标).可能会好奇为什么只更新那个下标更小的呢 ?
因为如果更新下标大的,而不更新下标小的,会出现这种情况:
当前询问区间左端点大于下标小的那个,那么显然下标大的继承不了下标小的的贡献.
为了避免这种情况,也就是说希望贡献给对未来没有影响的那个,我们只更新给下标更小的那个. (如果询问左端点小于下标小的点的话一定是能覆盖到的)
而下标大的点如何处理呢 ?
既然不对答案做贡献,我们将遇到的每一个重链都染成更大的下标. (显然我们以后要染的下标肯定都会大于该下标,所以肯定下标越大越好).
最难的部分处理完毕了,查询的时候直接在对应的线段树里查一个区间最大值即可.
#include<bits/stdc++.h>
#define maxn 200003
using namespace std;
void setIO(string s)
{
string in=s+".in", out=s+".out";
freopen(in.c_str(),"r",stdin);
// freopen(out.c_str(),"w",stdout);
}
int n,Q;
int dis[maxn],track[maxn];
char str[maxn];
namespace tr
{
int maxv[maxn<<2];
void update(int l,int r,int x,int k,int p)
{
if(l==r)
{
maxv[x]=p;
return;
}
int mid=(l+r)>>1;
if(k<=mid) update(l,mid,(x<<1),k,p);
else update(mid+1,r,(x<<1)|1,k,p);
maxv[x]=max(maxv[x<<1],maxv[(x<<1)|1]);
}
int query(int l,int r,int x,int L,int R)
{
if(l>=L&&r<=R) return maxv[x];
int mid=(l+r)>>1,tmp=0;
if(L<=mid) tmp=max(tmp,query(l,mid,x<<1,L,R));
if(R>mid) tmp=max(tmp,query(mid+1,r,(x<<1)|1,L,R));
return tmp;
}
};
namespace tree
{
#define lson ch[x][0]
#define rson ch[x][1]
int f[maxn],ch[maxn][30],pos[maxn],sta[maxn];
int get(int x)
{
return ch[f[x]][1]==x;
}
int isrt(int x)
{
return !(ch[f[x]][0]==x||ch[f[x]][1]==x);
}
void pushdown(int x)
{
if(!x)return;
if(pos[x])
{
if(lson) pos[lson]=pos[x];
if(rson) pos[rson]=pos[x];
}
}
void rotate(int x)
{
int old=f[x], fold=f[old],which=get(x);
if(!isrt(old)) ch[fold][ch[fold][1]==old]=x;
ch[old][which]=ch[x][which^1],f[ch[old][which]]=old;
ch[x][which^1]=old,f[old]=x,f[x]=fold;
}
void splay(int x)
{
int u=x,v=0,fa;
sta[++v]=u;
while(!isrt(u)) sta[++v]=f[u],u=f[u];
while(v) pushdown(sta[v--]);
for(u=f[u];(fa=f[x])!=u;rotate(x))
if(f[fa]!=u)
rotate(get(fa)==get(x)?fa:x);
}
void Access(int x,int co)
{
int t=0;
while(x)
{
splay(x);
if(pos[x]) tr::update(1,n,1,pos[x],dis[x]);
pos[x]=co, rson=t, t=x,x=f[x];
}
}
};
namespace SAM
{
int last,tot;
int ch[maxn][30],f[maxn];
void init()
{
last=tot=1;
}
void ins(int c,int o)
{
int np=++tot,p=last;
last=np,dis[np]=dis[p]+1;
while(p&&!ch[p][c]) ch[p][c]=np,p=f[p];
if(!p) f[np]=1;
else
{
int q=ch[p][c];
if(dis[q]==dis[p]+1) f[np]=q;
else
{
int nq=++tot;
dis[nq]=dis[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
f[nq]=f[q], f[np]=f[q]=nq;
while(p&&ch[p][c]==q) ch[p][c]=nq,p=f[p]; // 割裂操作
}
}
track[o]=np;
}
};
int answer[maxn];
struct OPT
{
int l,r,id;
}opt[maxn];
bool cmp(OPT a,OPT b)
{
return a.r<b.r;
}
int main()
{
// setIO("input");
SAM::init();
scanf("%d%d",&n,&Q);
scanf("%s",str+1);
for(int i=1;i<=n;++i) SAM::ins(str[i]-'0',i);
for(int i=2;i<=SAM::tot;++i) tree::f[i]=SAM::f[i];
for(int i=1;i<=Q;++i) scanf("%d%d",&opt[i].l,&opt[i].r),opt[i].id=i;
sort(opt+1,opt+1+Q,cmp);
for(int i=1,j=1;i<=n;++i)
{
tree::Access(track[i], i); // 打上 i 点的标记
while(opt[j].r==i && j<=Q)
{
answer[opt[j].id]=tr::query(1,n,1,opt[j].l,opt[j].r);
++j;
}
}
for(int i=1;i<=Q;++i) printf("%d\n",answer[i]);
return 0;
}
LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度 LCT+SAM+线段树的更多相关文章
- 【刷题】LOJ 6041 「雅礼集训 2017 Day7」事情的相似度
题目描述 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的有相同的事情发 ...
- 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\),那么两个前缀的最长公共后缀就 ...
- #6041. 「雅礼集训 2017 Day7」事情的相似度 [set启发式合并+树状数组扫描线]
SAM 两个前缀的最长后缀等价于两个点的 \(len_{lca}\) , 题目转化为求 \(l \leq x , y \leq r\) , \(max\{len_{lca(x,y)}\}\) // p ...
- 「雅礼集训 2017 Day7」事情的相似度
「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...
- 【LOJ 6041】「雅礼集训 2017 Day7」事情的相似度
Description 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的 ...
- LOJ6041. 「雅礼集训 2017 Day7」事情的相似度 [后缀树,LCT]
LOJ 思路 建出反串的后缀树,发现询问就是问一个区间的点的\(lca\)的深度最大值. 一种做法是dfs的时候从下往上合并\(endpos\)集合,发现插入一个点的时候只需要把与前驱后继的贡献算进去 ...
- 【loj6041】「雅礼集训 2017 Day7」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组
题目描述 给你一个长度为 $n$ 的01串,$m$ 次询问,每次询问给出 $l$ .$r$ ,求从 $[l,r]$ 中选出两个不同的前缀的最长公共后缀长度的最大值. $n,m\le 10^5$ 题解 ...
随机推荐
- Linux进程线程学习笔记:运行新程序
Linux进程线程学习笔记:运行新程序 周银辉 在上一篇中我们说到,当启动一个新进程以后,新进程会复制父进程的大部份上下 ...
- 实现MVC.NET 5的国际化
实现国际化有三种做法: 创建资源文件. 每种语言设置一套单独的View. 1 + 2. 通常而言,第一种方法的可维护性是最高的.因为随着项目的规模的扩大,为每种语言设置一套单独的View,前期的工作量 ...
- T470 Win10下触摸板手势
T470 Win10下触摸板手势 学习了:https://forum.51nb.com/thread-1742490-1-1.html 三指横向竟然是alt+tab 学习了:http://www.xi ...
- 2.6-NAT
2.6-NAT 网络地址转换协议NAT(Network Address Translation): 交换和远程都要用,先上什么就放在哪一块讲,具体来说NAT还是属于远程的. ...
- [Jest] Use property matchers in snapshot tests with Jest
With the right process in place, snapshot tests can be a great way to detect unintended changes in a ...
- Xcode 自己主动生成版本技术最佳实践
在 bloglovin ,我们使用自己主动生成版本来设置Xcode,使当前的版本为在Git活跃的分支上 的提交数. 它一直正常工作着.但我们的技术也不是一帆风顺的. 糟糕的老方法 我们使用的技术是来自 ...
- 支付宝即时到帐接口的python实现,演示样例採用django框架
因工作须要研究了支付宝即时到帐接口.并成功应用到站点上,把过程拿出来分享. 即时到帐仅仅是支付宝众多商家服务中的一个,表示客户付款,客户用支付宝付款.支付宝收到款项后,立即通知你,而且此笔款项与交易脱 ...
- luogu2320 鬼谷子的钱袋
题目大意 鬼谷子决定将自己的金币数好并用一个个的小钱袋装好,以便在他现有金币的支付能力下,任何数目的金币他都能用这些封闭好的小钱的组合来付账.求钱袋数最少,并且不有两个钱袋装有相同的大于1的金币数的装 ...
- bootstrap异步加载树后样式显示问题
整个过程: 1.先加载整个页面 2.通过jquery异步请求后台返回数据 3.循环遍历数据,拼接需要的内容 4.把拼接好的数据加载到页面中. 问题: 把拼接好的内容加载到页面后,样式显示不正确.而如果 ...
- 2749: [HAOI2012]外星人
首先像我一样把柿子画出来或者看下hint 你就会发现其实是多了个p-1这样的东东 然后除非是2他们都是偶数,而2就直接到0了 算一下2出现的次数就好 #include<cstdio> #i ...