首页 > 代码库 > BZOJ3879: SvT

BZOJ3879: SvT

后缀数组裸题,每次的查询单调栈扫一遍就完了。为什么要写虚后缀树= =后缀数组不是自带虚树的结构么= =

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5e5+5;
typedef int arr[N];
arr sa,r,f[19];
void pre(char*s,int n){
	static arr c,t;
	for(int i=0;i<n;++i)
		++c[s[i]];
	for(int i=1;i<127;++i)
		c[i]+=c[i-1];
	for(int i=n-1;~i;--i)
		sa[--c[s[i]]]=i;
	for(int i=1;i<n;++i)
		r[sa[i]]=r[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]);
	for(int j=1;;j<<=1){
		int k=j,m=r[sa[n-1]]+1;
		if(m==n)break;
		for(int i=0;i<j;++i)
			t[i]=n-j+i;
		for(int i=0;i<n;++i)
			if(sa[i]>=j)
				t[k++]=sa[i]-j;
		for(int i=0;i<m;++i)
			c[i]=0;
		for(int i=0;i<n;++i)
			++c[r[i]];
		for(int i=1;i<m;++i)
			c[i]+=c[i-1];
		for(int i=n-1;~i;--i)
			sa[--c[r[t[i]]]]=t[i];
		for(int i=0;i<n;++i)
			t[i]=r[i];
		r[sa[0]]=0;
		for(int i=1;i<n;++i)
			r[sa[i]]=r[sa[i-1]]+(t[sa[i]]!=t[sa[i-1]]||t[sa[i]+j]!=t[sa[i-1]+j]);
	}
}
bool foo(int i,int j){return r[i]<r[j];}
int ask(int i,int j){
	int k=__lg(j-i+1);
	return min(f[k][i],f[k][j-(1<<k)+1]);
}
int main(){
	int n,q,m;
	static char s[N];
	scanf("%d%d%s",&n,&q,s);
	pre(s,n+1);
	for(int i=0,j=0;i<n;++i){
		if(j)--j;
		while(s[i+j]==s[sa[r[i]-1]+j])
			++j;
		f[0][r[i]]=j;
	}
	for(int j=1;1<<j<n;++j)
		for(int i=1;i+(1<<j)-1<=n;++i)
			f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]);
	while(q--){
		static arr a,h,t;
		static ll z[N];
		scanf("%d",&m);
		for(int j=0;j<m;++j)
			scanf("%d",a+j),--a[j];
		sort(a,a+m,foo);
		m=unique(a,a+m)-a;
		for(int j=1;j<m;++j)
			h[j]=ask(r[a[j-1]]+1,r[a[j]]);
		h[m]=-1;
		for(int j=0;j<m;++j)
			z[j]=1;
		ll e=0;
		for(int i=0,j=1;j<=m;++j){
			for(;i&&h[j]<=h[t[i]];--i){
				e+=h[t[i]]*z[t[i-1]]*z[t[i]];
				z[t[i-1]]+=z[t[i]];
			}
			t[++i]=j;
		}
		printf("%lld\n",e);
	}
}

  

BZOJ3879: SvT