[bzoj4516] [SDOI2016]生成魔咒

Description

魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。

一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。

例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1]、

[1,1]、[1,1,1] 三种。最初 S 为空串。共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都

需要求出,当前的魔咒串 S 共有多少种生成魔咒。

Input

第一行一个整数 n。

第二行 n 个数,第 i 个数表示第 i 次操作加入的魔咒字符。

1≤n≤100000。,用来表示魔咒字符的数字 x 满足 1≤x≤10^9

Output

输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量

Sample Input

7
1 2 3 3 3 1 2

Sample Output

1
3
6
9
12
17
22

Solution

后缀数组。

把原串\(reverse\)一下,建出后缀数组,求一下\(height\)数组。

然后按后缀的字典序建一个链表,每次考虑把串第一个位置的后缀算出贡献,然后利用链表合并一下\(height\)就好了。

最后倒序前缀和输出答案就行了。

#include<bits/stdc++.h>
using namespace std;

#define ll long long 

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(ll x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 1e6+10;
const int inf = 1e9;

int n,w[maxn],r[maxn];

int spx[maxn],spy[maxn],sum[maxn],sa[maxn],rk[maxn],height[maxn],d[maxn][20],lg[maxn];

void build() {
	int m=n,p=0;int *x=spx,*y=spy;
	for(int i=1;i<=n;i++) sum[x[i]=w[i]]++;
	for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
	for(int i=n;i;i--) sa[sum[x[i]]--]=i;

	for(int k=1,tot=0;p<n;k<<=1,tot=0) {
		for(int i=n-k+1;i<=n;i++) y[++tot]=i;
		for(int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k;

		for(int i=1;i<=m;i++) sum[i]=0;
		for(int i=1;i<=n;i++) sum[x[y[i]]]++;
		for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
		for(int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];

		swap(x,y),x[sa[1]]=p=1;
		for(int i=2;i<=n;i++)
			if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) x[sa[i]]=++p;
			else x[sa[i]]=p;
		m=p;
	}

	for(int i=1;i<=n;i++) rk[sa[i]]=i;p=1;
	for(int i=1;i<=n;i++) {
		if(p) p--;
		while(w[i+p]==w[sa[rk[i]-1]+p]) p++;
		height[rk[i]]=p;
	}
}

ll tmp[maxn];
int pre[maxn],nxt[maxn];

int main() {
	read(n);for(int i=1;i<=n;i++) read(w[i]),r[i]=w[i];
	sort(r+1,r+n+1);int M=unique(r+1,r+n+1)-r-1;
	for(int i=1;i<=n;i++) w[i]=lower_bound(r+1,r+M+1,w[i])-r;
	reverse(w+1,w+n+1);
	build();

	for(int i=1;i<n;i++) nxt[i]=i+1;
	for(int i=2;i<=n;i++) pre[i]=i-1;

	for(int i=1;i<=n;i++) {
		int x=rk[i];
		int mn=max(height[x],height[nxt[x]]);
		tmp[i]=n-i+1-mn;
		height[nxt[x]]=min(height[nxt[x]],height[x]);
		height[x]=0;
		pre[nxt[x]]=pre[x];
		if(x) nxt[pre[x]]=nxt[x];
	}
	reverse(tmp+1,tmp+n+1);
	for(int i=1;i<=n;i++) tmp[i]+=tmp[i-1],write(tmp[i]);
	return 0;
}
posted @ 2019-01-14 21:06  Hyscere  阅读(133)  评论(0编辑  收藏  举报