AmazingCounters.com

[BZOJ]4199: [Noi2015]品酒大会(后缀数组+笛卡尔树)

Time Limit: 10 Sec  Memory Limit: 512 MB

Description

Input

Output

Sample Input

10
ponoiiipoi
2 1 4 7 4 8 3 6 4 7

Sample Output

45 56
10 56
3 32
0 0
0 0
0 0
0 0
0 0
0 0
0 0

HINT

 

Solution

  先求出后缀数组,两个后缀的最长公共前缀是它们之间height的最小值,对height建笛卡尔树,树上维护最大最小值即可。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
inline int read()
{
    int x,f=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=0;
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
    return f?x:-x;
}
#define MN 300000
int v[MN+5],ar[MN*4+10],*sa=ar,*nsa=sa+MN+2,*rk=nsa+MN+2,*nrk=rk+MN+2,h[MN+5];
int a[MN+5],z[MN+5],zn,lc[MN+5],rc[MN+5],sz[MN+5],mx[MN+5],mn[MN+5];
ll f1[MN+5],f2[MN+5];
char s[MN+5];
void dfs(int x)
{
    if(!x)return;
    int l=lc[x],r=rc[x];
    dfs(l);dfs(r);
    if(!l)l=MN+1,sz[l]=1,mx[l]=mn[l]=a[sa[x-1]];
    if(!r)r=MN+2,sz[r]=1,mx[r]=mn[r]=a[sa[x]];
    f1[h[x]]+=1LL*sz[l]*sz[r];
    f2[h[x]]=max(f2[h[x]],max(max(1LL*mn[l]*mn[r],1LL*mn[l]*mx[r]),
                              max(1LL*mx[l]*mn[r],1LL*mx[l]*mx[r])));
    sz[x]=sz[l]+sz[r];
    mn[x]=min(mn[l],mn[r]);
    mx[x]=max(mx[l],mx[r]);
}
int main()
{
    int n=read(),l,i,x;
    scanf("%s",s+1);
    for(i=1;i<=n;++i)a[i]=read();
    for(i=1;i<=n;++i)++v[s[i]];
    for(i='a';i<='z';++i)v[i]+=v[i-1];
    for(i=1;i<=n;++i)sa[v[s[i]]--]=i;
    for(i=1;i<=n;++i)rk[sa[i]]=rk[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]);
    for(l=1;l<n;l<<=1,swap(sa,nsa),swap(rk,nrk))
    {
        for(i=1;i<=n;++i)v[rk[sa[i]]]=i;
        for(i=n;i;--i)if(sa[i]>l)nsa[v[rk[sa[i]-l]]--]=sa[i]-l;
        for(i=0;i<l;++i)nsa[v[rk[n-i]]--]=n-i;
        for(i=1;i<=n;++i)nrk[nsa[i]]=nrk[nsa[i-1]]+(rk[nsa[i]]!=rk[nsa[i-1]]||rk[nsa[i]+l]!=rk[nsa[i-1]+l]);
    }
    for(i=1,l=0;i<=n;++i,l?--l:0)
        if(rk[i]>1){for(x=sa[rk[i]-1];s[i+l]==s[x+l];++l);h[rk[i]]=l;}
    for(i=2;i<=n;++i)
    {
        while(zn&&h[i]<h[z[zn]])lc[i]=z[zn--];
        rc[z[zn]]=i;z[++zn]=i;
    }
    memset(f2,200,sizeof(f2));
    dfs(z[1]);
    for(i=n;i--;)f1[i]+=f1[i+1],f2[i]=max(f2[i],f2[i+1]);
    for(i=0;i<n;++i)printf("%lld %lld\n",f1[i],f1[i]?f2[i]:0);
}

 

posted on 2017-05-04 16:30  ditoly  阅读(336)  评论(0编辑  收藏  举报