把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

题面传送门
智商不够,自动机和数据结构来凑。
考虑对原串建出SAM,那么两个前缀的最长公共后缀就是他们在SAM上LCA的深度。
那么我们其实要求的就是一段区间内的节点在一棵树上的LCA的最大深度。
考虑离线,按照右端点排序。从左往右扫。
如果对于两个节点\(u,v\)\(u<v\),且它们在树上处于同一深度,那么\(u\)显然是可以排除在外的。
所以我们用一个LCT维护这个parent tree,每次将一个点到根的路径打通并将路径上碰到的点放到树状数组上维护,每次查询在树状数组上查询后缀即可。
时间复杂度\(O(nlog^2n)\),然而常数小的出奇。时间瓶颈在LCT不在树状数组的nlogn次修改
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 200000
#define M 300000
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (m*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
using namespace std;
int n,m,x,y,Pl[N+5],Ans[N+5],d[N+5];char S[N+5];
struct Ques{int l,id;};vector<Ques> Q[N+5];
namespace BIT{
	int F[N+5];I void Get(int x,int y){while(x<=n) F[x]=max(F[x],y),x+=x&-x;}I int Qry(int x){int Ans=0;while(x) Ans=max(Ans,F[x]),x-=x&-x;return Ans;}
}
namespace SAM{
	int len[N+5],link[N+5],son[N+5][2],La=1,p,q,cnt=1;I void Ins(char c){
		c-='0';p=La;La=++cnt;len[La]=len[p]+1;while(p&&!son[p][c]) son[p][c]=La,p=link[p];if(!p){link[La]=1;return;}
		q=son[p][c];if(len[q]==len[p]+1)link[La]=q;else{
			link[++cnt]=link[q];link[q]=link[La]=cnt;memcpy(son[cnt],son[q],sizeof(son[q]));len[cnt]=len[p]+1;while(p&&son[p][c]==q)son[p][c]=cnt,p=link[p];
		}
	} 
}
namespace LCT{
	int l[N+5],r[N+5],F[N+5],Fl[N+5],fa[N+5],st[N+5],sh;I int CD(int x){return l[fa[x]]==x||r[fa[x]]==x;}I int RS(int x){return r[fa[x]]==x;}
	I void RO(int x){int y=fa[x],z=fa[y],b=(RS(x)?l[x]:r[x]);CD(y)&&((RS(y)?r[z]:l[z])=x);RS(x)?(l[x]=y,r[y]=b):(r[x]=y,l[y]=b);fa[y]=x;fa[x]=z;b&&(fa[b]=y);}
	I void PF(int x,int w){x&&(F[x]=Fl[x]=w);}I void PD(int x){Fl[x]&&(PF(l[x],Fl[x]),PF(r[x],Fl[x]),Fl[x]=0);} 
	I void SP(int x){int y=x;st[sh=1]=y;while(CD(y))y=fa[y],st[++sh]=y;while(sh) PD(st[sh--]);while(CD(x)) CD(fa[x])&&(RO(RS(x)^RS(fa[x])?x:fa[x]),0),RO(x);}
	I void AC(int x,int Id){int y=0;for(;x;x=fa[y=x]) SP(x),F[x]&&(/*printf("%d %d %d\n",Id,F[x],SAM::len[x]),*/BIT::Get(n-F[x]+1,SAM::len[x]),0),r[x]=y/*,printf(" %d %d ",x,y)*/;/*Pc('\n');*/PF(y,Id);}
}
int main(){
//	freopen("1.in","r",stdin);
	RI i,j;scanf("%d%d",&n,&m);scanf("%s",S+1);for(i=1;i<=n;i++) SAM::Ins(S[i]),Pl[i]=SAM::La;for(i=1;i<=SAM::cnt;i++) LCT::fa[i]=SAM::link[i];
	for(i=1;i<=m;i++)scanf("%d%d",&x,&y),Q[y].push_back((Ques){x,i});for(i=1;i<=n;i++)for(LCT::AC(Pl[i],i),j=0;j<Q[i].size();j++) Ans[Q[i][j].id]=BIT::Qry(n-Q[i][j].l+1);
	for(i=1;i<=m;i++) printf("%d\n",Ans[i]);
}
posted @ 2021-11-14 20:32  275307894a  阅读(33)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end