[LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大會

[LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大會

題意

給定一個長度爲 \(n\) 的字符串 \(s\), 對於全部 \(r\in[1,n]\) 求出 \(s\) 的全部LCP不小於 \(r\) 的後綴對的個數以及這些後綴對所能組成的最大權值.php

一個後綴對 \((a,b)\) 的權值是它們左端點的權值的積.c++

\(n\le 3\times 10^5\).spa

題解

好久之前寫的SAM沙雕題code

由於要求LCP因此咱們把這個串reverse一下用SAM搞.blog

根據後綴自動機的性質, 某兩個後綴的LCP就是它們在SAM上對應結點的LCA的 \(len\).字符串

那麼對於計數的部分, 咱們顯然只要對於每一個點都算出有多少個後綴以它爲LCA就能夠了.get

後面求最大權值的部分看上去好像只要記錄一會兒樹中的最大值和次大值就能夠了, 然而權值可能有負數因而還得記錄最小值和次小值.it

計算出每一個 \(len\) 的貢獻後取後綴和就能夠出答案了.ast

參考代碼

#include <bits/stdc++.h>

const int MAXN=6e5+10;
typedef long long int64;

struct Edge{
    int from;
    int to;
    Edge* next;
};
Edge E[MAXN];
Edge* head[MAXN];
Edge* top=E;

int n;
int cnt=1;
int root=1;
int last=1;
int v[MAXN];
char s[MAXN];
int len[MAXN];
int prt[MAXN];
int val[MAXN];
int size[MAXN];
int64 ans[MAXN];
int64 sum[MAXN];
int maxv[MAXN][2];
int minv[MAXN][2];
std::map<char,int> chd[MAXN];

void DFS(int);
void Insert(int,int);
void Extend(char,int);

int main(){
    memset(ans,0x80,sizeof(ans));
    memset(maxv,0x80,sizeof(maxv));
    memset(minv,0x7F,sizeof(minv));
    scanf("%d",&n);
    scanf("%s",s);
    for(int i=0;i<n;i++)
        scanf("%d",v+i);
    for(int i=1;i<=n;i++)
        Extend(s[n-i],v[n-i]);
    for(int i=2;i<=cnt;i++)
        Insert(prt[i],i);
    DFS(root);
    for(int i=n-1;i>=0;i--){
        sum[i]+=sum[i+1];
        ans[i]=std::max(ans[i],ans[i+1]);
    }
    for(int i=0;i<n;i++)
        printf("%lld %lld\n",sum[i],sum[i]==0?0:ans[i]);
    return 0;
}

void UpdateMax(int x,int v){
    maxv[x][1]=std::max(maxv[x][1],v);;
    if(maxv[x][0]<maxv[x][1])
        std::swap(maxv[x][0],maxv[x][1]);
}

void UpdateMin(int x,int v){
    minv[x][1]=std::min(minv[x][1],v);
    if(minv[x][0]>minv[x][1])
        std::swap(minv[x][0],minv[x][1]);
}

void DFS(int root){
    for(Edge* i=head[root];i!=NULL;i=i->next){
        DFS(i->to);
        sum[len[root]]+=1ll*size[root]*size[i->to];
        size[root]+=size[i->to];
        UpdateMin(root,minv[i->to][0]);
        UpdateMin(root,minv[i->to][1]);
        UpdateMax(root,maxv[i->to][0]);
        UpdateMax(root,maxv[i->to][1]);
    }
    if(size[root]>1)
        ans[len[root]]=std::max(ans[len[root]],std::max(1ll*minv[root][0]*minv[root][1],1ll*maxv[root][0]*maxv[root][1]));
}

void Extend(char x,int v){
    int p=last;
    int np=++cnt;
    size[last=np]=1;
    len[np]=len[p]+1;
    minv[np][0]=v;
    maxv[np][0]=v;
    while(p&&!chd[p].count(x))
        chd[p][x]=np,p=prt[p];
    if(p==0)
        prt[np]=root;
    else{
        int q=chd[p][x];
        if(len[q]==len[p]+1)
            prt[np]=q;
        else{
            int nq=++cnt;
            chd[nq]=chd[q];
            prt[nq]=prt[q];
            prt[q]=nq;
            prt[np]=nq;
            len[nq]=len[p]+1;
            while(p&&chd[p][x]==q)
                chd[p][x]=nq,p=prt[p];
        }
    }
}

void Insert(int from,int to){
    top->from=from;
    top->to=to;
    top->next=head[from];
    head[from]=top++;
}

相關文章
相關標籤/搜索