ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-07-07 14:02:59  阅读:187  来源: 互联网

标签:LCT 下标 SAM LOJ Access int maxn 涂色 重链


我们有一个经典模型:

两个串的最长公共后缀长度,是后缀树中两点 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; 
}

  

   

标签:LCT,下标,SAM,LOJ,Access,int,maxn,涂色,重链
来源: https://blog.51cto.com/u_15291195/3000596

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有