BZOJ 4199: [Noi2015]品酒大会 后缀自动机_逆序更新

BZOJ 4199: [Noi2015]品酒大会 后缀自动机_逆序更新

细节........

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#define setIO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 
#define maxn 1000006
#define inf -0x3f3f3f3f3f3f3f3fll 
#define ll long long 
using namespace std;
int n,is[maxn],appear[maxn];  
long long val[maxn],ans1[maxn],ans2[maxn],maxv[maxn],minv[maxn]; 
char str[maxn]; 
// struct Graph{
//     int head[maxn],to[maxn],nex[maxn],edges;
//     void addedge(int u,int v) { nex[++edges] = head[u],head[u] = edges,to[edges] = v; }
// }G; 
struct SAM{
    int f[maxn],cnt[maxn],ch[maxn][30],len[maxn],tot,last; 
    int C[maxn],rk[maxn]; 
    void init() { 
        tot = last = 1; 
        for(int i = 0;i < maxn; ++i) ans2[i] = inf; 
    }
    void ins(int c,int cur){
        int np = ++tot,p = last; len[np] = len[last] + 1, last = tot; 
        while(p && !ch[p][c]) ch[p][c] = np,p = f[p];
        if(!p) f[np] = 1;
        else{
            int q = ch[p][c]; 
            if(len[q] == len[p] + 1) f[np] = q;
            else {
                int nq = ++tot;
                len[nq] = len[p] + 1; 
                is[nq] = 1; 
                memcpy(ch[nq],ch[q],sizeof(ch[q])); 
                f[nq] = f[q],f[q] = f[np] = nq;
                while(p && ch[p][c] == q) ch[p][c] = nq,p = f[p];
            }
        }
        ++cnt[last];
        maxv[last] = val[cur];
        minv[last] = val[cur];
    }
    void build(){
        for(int i = 1;i <= tot; ++i) ++C[len[i]];
        for(int i = 1;i <= tot; ++i) C[i] += C[i - 1];
        for(int i = 1;i <= tot; ++i) rk[C[len[i]]--] = i; 
        for(int i = tot;i >= 1; --i) {
            int p = rk[i];
            ans1[len[f[p]]] += (long long)cnt[f[p]] * cnt[p];
            cnt[f[p]] += cnt[p];  
            if(is[f[p]] && !appear[f[p]]) 
            {
                appear[f[p]] = 1;
                minv[f[p]] = minv[p];
                maxv[f[p]] = maxv[p];
                continue;   
            }
            ans2[len[f[p]]] = max(ans2[len[f[p]]],maxv[p]*maxv[f[p]]); 
            ans2[len[f[p]]] = max(ans2[len[f[p]]],minv[p]*minv[f[p]]); 
            maxv[f[p]] = max(maxv[f[p]],maxv[p]); 
            minv[f[p]] = min(minv[f[p]],minv[p]); 
        }
    }
}sam; 
int main(){
    // setIO("input"); 
    scanf("%d",&n),scanf("%s",str),sam.init(); 
    for(int i = 0;i < n; ++i) scanf("%lld",&val[i]); 
    for(int i = n - 1;i >= 0; --i) sam.ins(str[i] - 'a',i);
    sam.build(); 
    for(int i = n - 1;i >= 0; --i) {
        ans1[i] += ans1[i + 1];
        ans2[i] = max(ans2[i],ans2[i+1]); 
    }
    for(int i = 0;i < n; ++i) {
        if(!ans1[i]) printf("%d %d\n",0,0);
        else printf("%lld %lld\n",ans1[i],ans2[i]); 
    }
    return 0; 
}

  

posted @ 2019-02-11 14:26 EM-LGH 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值