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


1 2 3 3 3 1 2

Sample Output





12 
17 
22

Hint

数据约束: 
对于 10% 的数据,1≤n≤10。 
对于 30% 的数据,1≤n≤100。 
对于 60% 的数据,1≤n≤1000。 
对于 100% 的数据,1≤n≤100000。 
用来表示魔咒字符的数字 x 满足 1≤x≤109。

 
题解:
SAM的裸题,但是打得后缀数组,显然是可以的,要求的是每个前缀的子串数,显然反转一下就变成了后缀的子串数
imagine一下求平时子串个数的过程,L-lcp+1 lcp为i和i+1的high[i] 显然这个题我们就可以类似的处理
加一个字符反转后就相当于加一个后缀,我们考虑他的贡献,显然之和他rk的前驱后继有关,于是我们减去原来的再加上现在的即可成为答案,前驱后继SET维护即可,或者玩玩SPLAY Treap也挺好
  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <set>
  8 using namespace std;
  9 const int N=100005,INF=2e8;
 10 int n,sa[N],rk[N],high[N],c[N],x[N],b[N],bc[N],num=0,s[N],y[N],bel[N];
 11 int gi(){
 12     int str=0;char ch=getchar();
 13     while(ch>'9' || ch<'0')ch=getchar();
 14     while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
 15     return str;
 16 }
 17 int midit(int x){
 18     int l=1,r=num,mid;
 19     while(l<=r){
 20         mid=(l+r)>>1;
 21         if(bc[mid]==x)return mid;
 22         if(x>bc[mid])l=mid+1;
 23         else r=mid-1;
 24     }
 25 }
 26 int k;
 27 bool comp(int i,int j){
 28     return y[i]==y[j] && y[i+k]==y[j+k];
 29 }
 30 void Getsa(){
 31     int m=num,t;
 32     for(int i=0;i<=m;i++)c[i]=0;
 33     for(int i=1;i<=n;i++)c[x[i]=bel[i]]++;
 34     for(int i=1;i<=m;i++)c[i]+=c[i-1];
 35     for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
 36     for(k=1;k<=n;k<<=1){
 37         t=0;
 38         for(int i=0;i<=m;i++)y[i]=0;
 39         for(int i=n-k+1;i<=n;i++)y[++t]=i;
 40         for(int i=1;i<=n;i++)if(sa[i]>k)y[++t]=sa[i]-k;
 41         for(int i=0;i<=m;i++)c[i]=0;
 42         for(int i=1;i<=n;i++)c[x[i]]++;
 43         for(int i=1;i<=m;i++)c[i]+=c[i-1];
 44         for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i];
 45         swap(x,y);
 46         x[sa[1]]=t=1;
 47         for(int i=2;i<=n;i++)x[sa[i]]=comp(sa[i-1],sa[i])?t:++t;
 48         if(t==n)break;
 49         m=t;
 50     }
 51     for(int i=1;i<=n;i++)rk[sa[i]]=i;
 52 }
 53 void Gethight(){
 54     int j,h=0;
 55     for(int i=1;i<=n;i++){
 56         j=sa[rk[i]-1];
 57         if(h)h--;
 58         for(;j+h<=n && i+h<=n;h++)if(s[i+h]!=s[j+h])break;
 59         high[rk[i]-1]=h;
 60     }
 61 }
 62 long long ans[N];
 63 set<int>p;
 64 int f[N][21];
 65 void prework(){
 66     int to;
 67     for(int i=1;i<=n;i++)f[i][0]=high[i];
 68     for(int j=1;j<=20;j++)
 69         for(int i=1,tmp=n-(1<<j)+1;i<=tmp;i++){
 70             to=i+(1<<(j-1));
 71             if(f[i][j-1]<f[to][j-1])f[i][j]=f[i][j-1];
 72             else f[i][j]=f[to][j-1];
 73     }
 74 }
 75 int query(int l,int r){
 76     int k=log(r-l+1)/log(2);
 77     return min(f[l][k],f[r-(1<<k)+1][k]);
 78 }
 79 int lcp(int i,int j){
 80     return query(i,j-1);
 81 }
 82 long long cnt[N];
 83 void Getanswer(){
 84     long long sum=0;
 85     int pre,nxt,now;
 86     set<int>::iterator iter;
 87     p.insert(n+1);p.insert(0);
 88     for(int i=n;i>=1;i--){
 89         now=rk[i];
 90         iter=(--p.lower_bound(now));
 91         if(iter!=p.begin()){
 92             pre=*(iter);
 93              sum-=cnt[pre];
 94             cnt[pre]=(n-sa[pre]+1-lcp(pre,now));
 95             sum+=cnt[pre];
 96         } 
 97         nxt=*(p.upper_bound(now));
 98         cnt[now]=(n-sa[now]+1-lcp(now,nxt));
 99         sum+=cnt[now];
100         ans[n-i+1]=sum;
101         p.insert(now);
102     }
103     for(int i=1;i<=n;i++)printf("%lld\n",ans[i]);
104 }
105 int main()
106 {
107     freopen("menci_incantation.in","r",stdin);
108     freopen("menci_incantation.out","w",stdout);
109     n=gi();
110     for(int i=1;i<=n;i++)s[i]=gi();
111     for(int i=1,t=n>>1;i<=t;i++)swap(s[i],s[n-i+1]);
112     for(int i=1;i<=n;i++)b[i]=s[i];
113     sort(b+1,b+n+1);for(int i=1;i<=n;i++)if(b[i]!=b[i+1])bc[++num]=b[i];
114     for(int i=1;i<=n;i++)bel[i]=midit(s[i]);
115     Getsa();Gethight();prework();Getanswer();
116     return 0;
117 }

 

posted @ 2017-07-15 20:22  PIPIBoss  阅读(300)  评论(0编辑  收藏  举报