1. 程式人生 > >【BZOJ】3145: [Feyat cup 1.5]Str-set&SA

【BZOJ】3145: [Feyat cup 1.5]Str-set&SA

傳送門:bzoj3145


題解

完全是膜著Claris的code寫的,程式碼就不用看了。。。

不考慮複雜度我們可以列舉 i , j i,j 分別表示串 S ,

T S,T 中那個不同的位置。
a n s = m a x
( l c s ( i 1 , j
1 ) + l c p ( i + 1 , j + 1 ) ) + 1 ans=max(lcs(i-1,j-1)+lcp(i+1,j+1))+1

可以在 S S 末尾加一個字符集外的字元後再連上 T T 。正著求出 l c p lcp 翻轉後求出 l c s lcs

可以通過固定一維列舉另一維 O ( n 2 ) O(n^2) 的複雜度降到 O ( n log n ) O(n\log n) :從大到小列舉 l c p lcp 的值,即按 h e i g h t i height_i 排序,並查集維護 h e i g h t l c p height\geq lcp 的連續區間啟發式合併 i 1 , i i-1,i 所在的區間,逐個插入更新答案。

每段連續區間中 s e t set 維護這些串對應的在 S , T S,T 中的 l c s lcs r a n k rank ,對於插入的串找到集合中最接近它對應的字首 r a n k rank 求個 l c s lcs 即可。

注意以上都是強制 l c s , l c p lcs,lcp > 0 >0 的情況,還有可能只有 l c s / l c p lcs/lcp ,需要最後特殊列舉判斷一下。


程式碼

#include<bits/stdc++.h>
#define mem(f) memset(f,0,sizeof(f))
using namespace std;
const int N=4e5+100;

int n,la,lb,d[18][N],bin[30],lg[N],id[N],sz[N];
int c[N],t1[N],t2[N],f[N],ans,lcp;
int head[N],nxt[N<<1],to[N<<1],tot;
char s[N],t[N];bool ca[N],cb[N];
set<int>sa[N],sb[N];
set<int>::iterator it;

inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}

struct SA{
	int sa[N],rk[N],ht[N];char s[N];
	inline void build()
	{
		int i,j,k,p,m=128,*x=t1,*y=t2;
		for(i=1;i<=n;++i) c[(x[i]=(int)s[i])]++;
		for(i=1;i<=m;++i) c[i]+=c[i-1];
		for(i=n;i;--i) sa[c[x[i]]--]=i;
		for(k=1;k<=n;k<<=1){
			for(p=0,i=n-k+1;i<=n;++i) y[++p]=i;
			for(i=1;i<=n;++i) if(sa[i]>k) y[++p]=sa[i]-k;
			for(i=1;i<=m;++i) c[i]=0;
			for(i=1;i<=n;++i) c[x[y[i]]]++;
			for(i=1;i<=m;++i) c[i]+=c[i-1];
			for(i=n;i;--i) sa[c[x[y[i]]]--]=y[i];
			p=1;swap(x,y);x[sa[1]]=1;
			for(i=2;i<=n;++i){
				p+=((y[sa[i]]!=y[sa[i-1]])||(y[sa[i]+k]!=y[sa[i-1]+k]));
				x[sa[i]]=p;
			}
			if(p>=n) break;
			m=p;
		}
		for(i=1;i<=n;++i) rk[sa[i]]=i;
		for(p=0,i=1;i<=n;++i){
			if(rk[i]==1) {p=0;continue;}
			for(p=max(0,p-1),j=sa[rk[i]-1];i+p<=n && j+p<=n && s[i+p]==s[j+p];++p);
			ht[rk[i]]=p;
		}
	}
	inline void mk()
	{
		int i,j;bin[0]=1;
		for(i=1;i<30;++i) bin[i]=bin[i-1]<<1;
		for(i=2;i<N;++i) lg[i]=lg[i>>1]+1;
		for(i=1;i<=n;++i) d[0][i]=ht[i];
		for(i=1;bin[i]<=n;++i)
		 for(j=1;j+bin[i]-1<=n;++j)
		  d[i][j]=min(d[i-1][j],d[i-1][j+bin[i-1]]);
	}
}A,B;

inline int cal(int x,int y)
{
	if(x>y) swap(x,y);int bs=lg[y-x];
	return min(d[bs][x+1],d[bs][y-bin[bs]+1]);
}

void dfs(int x,int fr,int bl)
{
	int i,j;f[x]=bl;
	if(A.sa[x]<=la){
		i=A.sa[x]-2;if(i>0){
			i=B.rk[n-i+1];sa[bl].insert(i);
			it=sb[bl].lower_bound(i);
			if(it!=sb[bl].end()) ans=max(ans,lcp+cal(i,*it));
			if(it!=sb[bl].begin()) it--,ans=max(ans,lcp+cal(i,*it));
		}
	}else if(A.sa[x]>la+1){
		i=A.sa[x]-2;if(i>la+1){
			i=B.rk[n-i+1];sb[bl].insert(i);
			it=sa[bl].lower_bound(i);
			if(it!=sa[bl].end()) ans=max(ans,lcp+cal(i,*it));
			if(it!=sa[bl].begin()) it--,ans=max(ans,lcp+cal(i,*it));
		}
	}
	for(i=head[x];i;i=nxt[i]) if(to[i]!=fr) dfs(to[i],x,bl);
}

inline void ext(int x,int y)
{
	x=f[x];y=f[y];
	if(sz[x]>sz[y]) swap(x,y);
	if((ca[x]&&cb[y])||(cb[x]&&ca[y])) ans=max(ans,lcp-1);
	ca[y]|=ca[x];cb[y]|=cb[x];sz[y]+=sz[x];
	sa[x].clear();sb[x].clear();
	lk(x,y);lk(y,x);dfs(x,y,y); 
}

inline bool cmp(const int&x,const int&y){return A.ht[x]>A.ht[y];}

int