luoguP2178 [NOI2015]品酒大会(后缀自动机)

题意

承接上篇题解

考虑两个后缀的\(lcp\)是什么,是将串反着插入后缀自动机后两个前缀(终止节点)的\(lca\)!!!于是可以在parent tree上DP了。

比后缀数组又简单又好写跑的还快。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3*1e5+10;
int n,last,tot,cnt;
int head[maxn<<1],size[maxn<<1];
ll inf;
ll a[maxn],val[maxn<<1],maxx[maxn<<1],minn[maxn<<1],ans1[maxn],ans2[maxn];
char s[maxn];
struct edge{int to,nxt;}e[maxn<<1];
struct SAM
{
	int fa,len;
	int ch[30];
}sam[maxn<<1];
inline ll read()
{
	char c=getchar();ll res=0,f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
	return res*f;
}
inline void add(int u,int v){e[++cnt].nxt=head[u];head[u]=cnt;e[cnt].to=v;}
inline void sam_init(){sam[0].fa=-1;sam[0].len=0;last=0;}
inline void sam_add(int c,int id)
{
	int now=++tot;sam[now].len=sam[last].len+1;size[now]=1;val[now]=a[id];
	int p=last;last=now;
	while(~p&&!sam[p].ch[c])sam[p].ch[c]=now,p=sam[p].fa;
	if(p==-1){sam[now].fa=0;return;}
	int q=sam[p].ch[c];
	if(sam[q].len==sam[p].len+1)sam[now].fa=q;
	else
	{
		int nowq=++tot;
		sam[nowq].len=sam[p].len+1;
		memcpy(sam[nowq].ch,sam[q].ch,sizeof(sam[q].ch));
		sam[nowq].fa=sam[q].fa,sam[q].fa=sam[now].fa=nowq;
		while(~p&&sam[p].ch[c]==q)sam[p].ch[c]=nowq,p=sam[p].fa;
	}
}
void dfs(int x)
{
	maxx[x]=-inf,minn[x]=inf;
	if(size[x])maxx[x]=minn[x]=val[x];
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		dfs(y);
		if(minn[x]!=inf&&minn[y]!=inf&&maxx[x]!=-inf&&maxx[x]!=-inf)
			ans2[sam[x].len]=max(ans2[sam[x].len],max(maxx[x]*maxx[y],minn[x]*minn[y]));
		maxx[x]=max(maxx[x],maxx[y]),minn[x]=min(minn[x],minn[y]);
		ans1[sam[x].len]+=1ll*size[x]*size[y];
		size[x]+=size[y];
	}
}
int main()
{
	n=read();
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)a[i]=read();
	sam_init();
	for(int i=n;i;i--)sam_add(s[i]-'a',i);
	for(int i=1;i<=tot;i++)add(sam[i].fa,i);
	memset(ans2,-0x3f,sizeof(ans2));inf=-ans2[0];
	dfs(0);
	for(int i=n-1;~i;i--)ans1[i]+=ans1[i+1],ans2[i]=max(ans2[i],ans2[i+1]);
	for(int i=0;i<n;i++)
		if(ans1[i])printf("%lld %lld\n",ans1[i],ans2[i]);
		else puts("0 0");
	return 0;
}
posted @ 2019-12-17 14:27  nofind  阅读(104)  评论(0编辑  收藏  举报