BZOJ4516:[Sdoi2016]生成魔咒

4516: [Sdoi2016]生成魔咒

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1121  Solved: 623
[Submit][Status][Discuss]

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
思路{
  我们可以轻松求出插入之后的本质不同的子串个数。
  怎么乱搞呢?
  我们从后往前考虑:{
    加入一个数就是加入一个后缀:那我们直接统计这个后缀的贡献值都可以了。
    在非动态的情况下,每一个的贡献是n-height[i]+1;
    在动态的情况下,那每个的贡献就是(n-(rnk的前驱或后继)的LCP最大值+1);
    那我们用set或treap或Splay维护一下即可。
  }
}
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define il inline
#define RG register
#define db double
#define LL long long
#define maxx 100010
using namespace std;
set<LL> q;
set<LL>::iterator it;
LL a[maxx],tong[maxx],X[maxx],Y[maxx],height[maxx],rnk[maxx],f[maxx][19],pre[maxx],nxt[maxx],ans[maxx],sa[maxx];
il bool comp(LL *r,LL a,LL b,LL len){return r[a]==r[b]&&r[len+b]==r[len+a];}
il void build_sa(LL n){
	LL *x=X,*y=Y,*t,Max=maxx-1;
	for(RG LL i=0;i<n;++i)tong[x[i]=a[i]]++;
	for(RG LL i=1;i<=Max;++i)tong[i]+=tong[i-1];
	for(RG LL i=n-1;i!=-1;i--)sa[--tong[x[i]]]=i;
	for(RG LL j=1,i,p=0;p<n;j<<=1,Max=p){
		for(i=n-1,p=0;i>=n-j;--i)y[p++]=i;
		for(i=0;i<n;++i)if(sa[i]>=j)y[p++]=sa[i]-j;
		for(i=0;i<=Max;++i)tong[i]=0;
		for(i=0;i<n;++i)tong[x[y[i]]]++;
		for(i=1;i<=Max;++i)tong[i]+=tong[i-1];
		for(i=n-1;i>=0;i--)sa[--tong[x[y[i]]]]=y[i];
		for(i=1,p=1,t=x,x=y,y=t,x[sa[0]]=0;i<n;++i)
			x[sa[i]]=comp(y,sa[i-1],sa[i],j)?p-1:p++;
	}
}
LL n;
il void geth(){
	RG LL i,j,k=0;
	for(i=1;i<=n;++i)rnk[sa[i]]=i;
	for(i=0;i<n;height[rnk[i++]]=k)
		for((k?k--:0),j=sa[rnk[i]-1];a[j+k]==a[i+k];k++);
}
void RMQ(){
  for(int i=1;i<=n;++i)f[i][0]=height[i];
  for(int j=1;(1<<j)<=n;++j)
    for(int i=1;i+(1<<(j-1))-1<=n;++i)
      f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
LL LCP(int x,int y){
  if(x==y)return n-x+1; 
  x=rnk[x],y=rnk[y];if(x>y)swap(x,y);x++;
  int t=(int)(log(double(y-x+1))/log(2.000));
  return min(f[x][t],f[y-(1<<t)+1][t]);
}
il void update(LL x,LL y,LL kind){x=sa[x],y=sa[y];if(kind)pre[x]=y;else nxt[x]=y;}
LL sub[maxx];
il void luangao(){
	for(int i=0;i<n;++i)sub[i]=a[i];  
    sort(sub,sub+n);  int size=unique(sub,sub+n)-sub;  
    for(int i=0;i<n;i++)  
    a[i]=lower_bound(sub,sub+size,a[i])-sub+1;
}
il void work(){
	scanf("%lld",&n);
	for(RG LL i=n-1;i!=-1;--i)scanf("%lld",&a[i]);luangao();
	a[n]=0;build_sa(n+1),geth();RMQ();
	for(RG LL i=n-1;i!=-1;i--){
		bool flag1=false,flag2=false;
		q.insert(rnk[i]),it=q.find(rnk[i]);
		if(it!=q.begin())it--,update(rnk[i],*it,1),it++,flag1=true;
		if((++it)!=q.end())update(rnk[i],*it,0),flag2=true;
		LL now=n-i,lcp=0;if(flag1)lcp=LCP(i,pre[i]);
		if(flag2)lcp=max(lcp,LCP(i,nxt[i]));
		ans[now]=now-lcp+ans[now-1];
	}for(RG LL i=1;i<=n;++i)cout<<ans[i]<<"\n";
}
int main(){
	freopen("menci_incantation.in","r",stdin);
	freopen("menci_incantation.out","w",stdout);
    work();return 0;
}

 

posted @ 2017-07-08 21:54  QYP_2002  阅读(178)  评论(0编辑  收藏  举报