后缀树简短实现

也没什么好讲的,背下来也没什么问题。

不过理解更好吧。

对应洛谷后缀自动机的模板题

。。。。。。。。。。。。。

虽然后缀树很强,但是请注意:

常数还是有的(而且比较大。。。。,估计是唯一不如后缀自动机的地方)

节点数很难超过1.5*n,考场上可以试试卡卡空间什么的

#include <cstdio>
#include <cstring>
#define sid 2000500
#define inf 100000000
#define ri register int
#define ll long long
using namespace std;

template <typename re>
inline void upmax(re &a, re b) { if(a < b) a = b; }

char s[1000050];

struct P {
    int lef, len, link;
    int go[27];
} t[sid];
int cnt = 1, act = 1, rem, n;
ll ans;

int node(int l, int len) {
    t[++ cnt].lef = l; t[cnt].len = len; t[cnt].link = 1;
    return cnt;
}
void attend(int i) {
    n ++; s[i] = s[i] - 'a';
    int x = s[i], lst = 1; 
    rem ++;
    while(rem) {
        while(rem > t[t[act].go[s[n - rem + 1]]].len)
            rem -= t[act = t[act].go[s[n - rem + 1]]].len;
        int tar = s[n - rem + 1], &d = t[act].go[tar];
        int c = s[t[d].lef + rem  - 1];
        if(!d || x == c) {
            t[lst].link = act; lst = act;
            if(!d) d = node(n - rem + 1, inf);
            else return;
        }
        else {
            int np = node(t[d].lef, rem - 1);
            t[np].go[x] = node(n, inf); t[np].go[c] = d; 
            t[d].lef += rem - 1; t[d].len -= rem - 1;
            t[lst].link = d = np; lst = d;
        }
        (act == 1) ? rem -- : act = t[act].link;
    }
}

int has[sid];
void dfs(int e, int dep) {
    int p = 0;
    if(dep > n) has[e] ++;
    for(int i = 0; i <= 26; i ++) {
        int d = t[e].go[i];
        if(!d) continue;
        dfs(d, dep + t[d].len);
        has[e] += has[d];
    }
    if(has[e] >= 2) upmax(ans, 1ll * has[e] * dep);
}

int main() {
    scanf("%s", s + 1);
    int n = strlen(s + 1); s[++ n] = 'z' + 1;
    t[0].len = inf;
    for(ri i = 1; i <= n; i ++) attend(s[i]);
    dfs(1, 0);
    printf("%lld\n", ans);
    return 0;
}

 

posted @ 2018-05-06 16:55  remoon  阅读(886)  评论(1编辑  收藏  举报