bzoj千题计划257:bzoj4199: [Noi2015]品酒大会

http://www.lydsy.com/JudgeOnline/problem.php?id=4199

 

求出后缀数组的height

从大到小枚举,合并

维护组内 元素个数,最大、次大、最小、次小

 

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 300001

char s[N];
int n,a[N],b[N];

int p,q=1;
int v[N];
int sa[2][N],rk[2][N],height[N];

vector<int>V[N];

int fa[N],siz[N];
long long sum[N],mx[N];
int mx1[N],mx2[N],mi1[N],mi2[N];

int MX1,MX2,MI1,MI2;

void read (int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    x*=f;
}

void mul(int k,int *sa,int *rk,int *SA,int *RK)
{
    for(int i=1;i<=n;++i) v[rk[sa[i]]]=i;
    for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;    
    for(int i=n-k+1;i<=n;++i) SA[v[rk[i]]--]=i;
    for(int i=1;i<=n;++i) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);
}

void presa()
{
    for(int i=1;i<=n;++i) v[a[i]]++;
    for(int i=1;i<=26;++i) v[i]+=v[i-1];
    for(int i=1;i<=n;++i) sa[p][v[a[i]]--]=i;
    for(int i=1;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
    for(int k=1;k<n;k<<=1,swap(p,q)) 
    mul(k,sa[p],rk[p],sa[q],rk[q]);
}

void get_height()
{
    int j;
    for(int i=1,k=0;i<=n;++i)
    {
        j=sa[p][rk[p][i]-1];
        while(a[i+k]==a[j+k]) k++;
        height[rk[p][i]]=k;
        if(k) k--;
    }
}

int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); }

void unionn(int x,int y,int i)
{
    x=find(x);
    y=find(y);
    sum[i]+=1LL*siz[x]*siz[y];
    siz[y]+=siz[x];
    if(mx2[x]>=mx1[y])
    {
        mx2[y]=mx2[x];
        mx1[y]=mx1[x];
    }
    else 
    {
        if(mx2[x]>mx2[y]) mx2[y]=mx2[x];
        if(mx1[x]>=mx1[y])
        {
            mx2[y]=mx1[y];
            mx1[y]=mx1[x];
        }
        else if(mx1[x]>mx2[y]) mx2[y]=mx1[x];
    }
    if(mi2[x]<=mi1[y])
    {
        mi2[y]=mi2[x];
        mi1[y]=mi1[x];
    }
    else
    {
        if(mi2[x]<mi2[y]) mi2[y]=mi2[x];
        if(mi1[x]<=mi1[y])
        {
            mi2[y]=mi1[y];
            mi1[y]=mi1[x];
        }
        else if(mi1[x]<mi2[y]) mi2[y]=mi1[x];
    }
    mx[i]=max(mx[i],max(1LL*mx1[y]*mx2[y],1LL*mi1[y]*mi2[y]));
    fa[x]=y;
}
    
void solve()
{
    for(int i=1;i<=n;++i) 
    {
        fa[i]=i;
        siz[i]=1;
        mx[i]=-1e18;
        mx1[i]=b[i];
        mx2[i]=-1e9;
        mi1[i]=b[i];
        mi2[i]=1e9;
    }
    for(int i=2;i<=n;++i) V[height[i]].push_back(i);
    int s,w;
    for(int i=n;i;--i)
    {
        s=V[i].size();
        for(int j=0;j<s;++j)
        {
            w=V[i][j];
            if(find(sa[p][w-1])!=find(sa[p][w])) unionn(sa[p][w-1],sa[p][w],i);
            if(w<n && height[w+1]>=i && find(sa[p][w])!=find(sa[p][w+1])) unionn(sa[p][w+1],sa[p][w],i);
        }
    }
    for(int i=n-1;i;--i)
    {
        sum[i]+=sum[i+1];
        mx[i]=max(mx[i],mx[i+1]);
    }
    cout<<1LL*n*(n-1)/2<<' '<<max(1LL*MX1*MX2,1LL*MI1*MI2)<<'\n';
    for(int i=1;i<n;++i) 
    {
        cout<<sum[i]<<' ';
        if(!sum[i]) cout<<0<<'\n';
        else cout<<mx[i]<<'\n';
    }
}

int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    for(int i=1;i<=n;++i) a[i]=s[i]-'a'+1;
    MX1=MX2=-1e9;
    MI1=MI2=1e9;
    for(int i=1;i<=n;++i) 
    {
        read(b[i]);
        if(b[i]>=MX1)
        {
            MX2=MX1;
            MX1=b[i];
        }
        else if(b[i]>MX2) MX2=b[i];
        if(b[i]<=MI1) 
        {
            MI2=MI1;
            MI1=b[i];
        }
        else if(b[i]<MI2) MI2=b[i];
    }
    presa();
    get_height();
    solve();
}

 

posted @ 2018-03-05 16:52  TRTTG  阅读(200)  评论(0编辑  收藏  举报