WA70后缀数组写法求调
查看原帖
WA70后缀数组写法求调
613082
qscisQJing楼主2024/10/16 09:15

大概思路是求完 heightheight 数组之后用并查集维护从大到小的合并。应该是合并策略有错或是后半部分细节有错。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+5;
#define ll long long
char a[MAXN],b[MAXN],s[MAXN];
int n,k,sa[MAXN<<1],rk[MAXN<<1],oldrk[MAXN<<1];
int h[MAXN],p[MAXN];
int fa[MAXN],suma[MAXN],sumb[MAXN];
ll ans;
int find(int x)
{
	if(!x)return 0;
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
}
void merge(int x,int y,int v)
{
	v=min(v,k);
	x=find(x),y=find(y);
	if(x==y)return;
	if(!x||!y)return;
	fa[x]=y;
	int sa1=suma[x],sb1=sumb[x],sa2=suma[y],sb2=sumb[y];
	if(sa1-sb1<0&&sa2-sb2>0)
	{
		ans+=v*min(-sa1+sb1,sa2-sb2);
	}
	if(sa1-sb1>0&&sa2-sb2<0)
	{
		ans+=v*min(sa1-sb1,-sa2+sb2);
	}
	suma[y]+=sa1,sumb[y]+=sb1;
}
int main()
{
	cin>>n>>k;
	scanf("%s",a+1);
	scanf("%s",b+1);
	for(int i=1;i<=2*n+1;i++)
	{
		s[i]=i>n?b[i-n-1]:a[i];
	}
	s[n+1]='&';
	n=2*n+1;
	for(int i=1;i<=n;i++)sa[i]=i,rk[i]=s[i];
	for(int w=1;w<n;w<<=1)
	{
		sort(sa+1,sa+1+n,[&](int x,int y){
		return rk[x]==rk[y]?rk[x+w]<rk[y+w]:rk[x]<rk[y];
		});
		memcpy(oldrk,rk,sizeof rk);
		for(int i=1,p=0;i<=n;i++)
		{
			if(oldrk[sa[i]]==oldrk[sa[i-1]]&&
			oldrk[sa[i]+w]==oldrk[sa[i-1]+w])rk[sa[i]]=p;
			else rk[sa[i]]=++p;
		}
	}
	n>>=1;
	for(int i=1;i<=n-k+1;i++)suma[rk[i]]++;
	for(int i=n+2;i<=2*n+2-k;i++)sumb[rk[i]]++;
	n=n*2+1;
	int c=0;
	for(int i=1;i<=n;i++)
	{
		p[i]=i;
		if(rk[i]==1)continue;
		if(c)c--;
		while(s[i+c]==s[sa[rk[i]-1]+c])c++;
		h[rk[i]]=c;
	}
	sort(p+1,p+1+n,[&](int x,int y){return h[x]>h[y];});
	for(int i=1;i<=n;i++)
	{
		fa[p[i]]=p[i];
		if(!fa[p[i]-1])
		{
			fa[p[i]-1]=p[i]-1;
			merge(p[i]-1,p[i],h[p[i]]);
			fa[p[i]-1]=0;suma[p[i]-1]=sumb[p[i]-1]=0;
		}
		merge(p[i]-1,p[i],h[p[i]]);
		merge(p[i],p[i]+1,h[p[i]]);
	}
//	for(int i=1;i<=n;i++)cout<<rk[i]<<" ";puts("");
//	for(int i=1;i<=n;i++)cout<<h[i]<<" ";puts("");
	n>>=1;
	ans=1ll*(n-k+1)*k-ans;
	cout<<ans;
	return 0;
}
/*
5 1
aaaaa
aaaaa
*/
2024/10/16 09:15
加载中...