loj#3055. 「HNOI2019」JOJO 题目描述 题解 code

loj#3055. 「HNOI2019」JOJO
题目描述
题解
code
loj#3055. 「HNOI2019」JOJO
题目描述
题解
code

题解

并没有注意到相邻串字母不同,x=1想到用辅助数组加速跳next

首先显然离线,对每一段末尾求next,next的定义修改为匹配到的位置一定所在串的末尾

第一段长度大于等于,其他段长度刚好等于,把每一段当作特殊字符来做kmp,在找的时候算答案,答案是若干等差数列之和

由于kmp时间均摊,所以直接跳会被卡,因此如果长度大于一半的话就判断然后跳到周期等差数列的开头,时间是log的

总时间为O(nlog|S|)

code

实际上暴力跳也可以

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define mod 998244353
#define ll long long
#define file
using namespace std;

int a[100011][2],A[100011][2],ls[100011],d[100011][2],id[100011],nx[100011],n,i,j,k,l,len,tot,tp;
ll ans,Len[100011],Ans[100001];
vector<int> b[100011];
char ch;

void New(int x,int y,int s1,int s2) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;A[len][0]=s1,A[len][1]=s2;}
void dfs(int t,ll ans)
{
	ll ANS=ans;
	int i;
	
	j=b[t].size();
	fo(i,0,j-1)
	Ans[b[t][i]]=ans;
	
	for (i=ls[t]; i; i=a[i][1])
	{
		++tot;d[tot][0]=A[i][0],d[tot][1]=A[i][1];Len[tot]=Len[tot-1]+A[i][1];
		
		if (tot==1) nx[tot]=0,ans=(1ll*A[i][1]*(A[i][1]-1)/2)%mod;
		else
		{
			nx[tot]=nx[tot-1];l=0;
			while (nx[tot] && !(d[nx[tot]+1][0]==d[tot][0] && d[nx[tot]+1][1]==d[tot][1]))
			{
				if (d[nx[tot]+1][0]==d[tot][0] && d[nx[tot]+1][1]>l)
				{
					k=min(d[nx[tot]+1][1],A[i][1]);
					ans=(ans+Len[nx[tot]]*(k-l)%mod+(1ll*(l+1+k)*(k-l)/2)%mod)%mod;
					l=k;
				}
				
				if (Len[nx[nx[tot]]]>Len[nx[tot]]/2)
				{
					if (!(d[nx[nx[tot]]+1][0]==d[tot][0] && (d[nx[nx[tot]]+1][1]>l || d[nx[nx[tot]]+1][1]==d[tot][1])))
					nx[tot]-=((Len[nx[tot]]-(Len[nx[tot]]/2+1))/(Len[nx[tot]]-Len[nx[nx[tot]]]))*(nx[tot]-nx[nx[tot]]);
				}
				nx[tot]=nx[nx[tot]];
			}
			k=min(d[nx[tot]+1][1],A[i][1]);
			if (d[nx[tot]+1][0]==d[tot][0])
			{
				ans=(ans+Len[nx[tot]]*(k-l)%mod+(1ll*(l+1+k)*(k-l)/2)%mod)%mod;
				l=k;
				ans=(ans+Len[1]*(A[i][1]-k))%mod;
			}
			
			nx[tot]+=(d[nx[tot]+1][0]==d[tot][0] && d[nx[tot]+1][1]<=d[tot][1]);
		}
		
		dfs(a[i][0],ans);
		ans=ANS,--tot;
	}
}

int main()
{
//	#ifdef file
//	freopen("jojo6.in","r",stdin);
//	#endif
//	freopen("b.out","w",stdout);
	
	scanf("%d",&n);
	l=tot=1;id[0]=1;
	fo(i,1,n)
	{
		scanf("%d",&tp);
		if (tp==1)
		{
			scanf("%d%c%c",&j,&ch,&ch);
			++tot;
			New(l,tot,ch-'a'+1,j);
			l=tot;
		}
		else
		{
			scanf("%d",&j);
			l=id[j];
		}
		b[l].push_back(i);id[i]=l;
	}
	
	tot=0;
	dfs(1,0);
	fo(i,1,n) printf("%lld
",Ans[i]);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}