首页 > 其他 > 详细

BZOJ3926 [Zjoi2015]诸神眷顾的幻想乡【广义后缀自动机】

时间:2020-04-17 10:46:40      阅读:75      评论:0      收藏:0      [点我收藏+]

BZOJ3926[Zjoi2015]诸神眷顾的幻想乡

给出一棵树,问树上任意两点的简单路径能形成的不同字符串有多少个
相当于以每个叶子节点为根的\(Trie\)都加入到\(SAM\)里去然后找不同字串个数
这里考虑在线做广义\(SAM\)

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 4e6+7;
int n,m,col[MAXN];
vector<int> G[MAXN];
struct EXSAM{
    int len[MAXN],link[MAXN],ch[MAXN][10],tot,last,sta[MAXN],par[MAXN];
    EXSAM(){ tot = last = 1; }
    void extend(int c){
        int np = 0, p = last;
        if(!ch[p][c]) last = np = ++tot, len[np] = len[p] + 1;
        while(p and !ch[p][c]){
            ch[p][c] = np;
            p = link[p];
        }
        if(!p) link[np] = 1;
        else{
            int q = ch[p][c];
            if(len[p] + 1 == len[q]) np?link[np]=q:last=q;
            else{
                int clone = ++tot;
                len[clone] = len[p] + 1;
                link[clone] = link[q];
                memcpy(ch[clone],ch[q],sizeof(ch[q]));
                while(p and ch[p][c]==q){
                    ch[p][c] = clone;
                    p = link[p];
                }
                link[q] = clone;
                if(np) link[np] = clone;
                else last = clone;
            }
        }
    }
    void bfs(int u){
        queue<int> que;
        que.push(u);
        sta[par[u]=0] = 1;
        while(!que.empty()){
            u = que.front(); que.pop();
            last = sta[par[u]], extend(col[u]), sta[u] = last;
            for(int i = 0; i < (int)G[u].size(); i++) if(G[u][i]!=par[u]){
                par[G[u][i]] = u;
                que.push(G[u][i]);
            }       
        }
    }
    long long query(){
        long long ret = 0;
        for(int i = 2; i <= tot; i++) ret += len[i] - len[link[i]];
        return ret;
    }
}sam;
int main(){
    scanf("%d %d",&n,&m);
    for(int i = 1; i <= n; i++) scanf("%d",&col[i]);
    for(int i = 1; i < n; i++){
        int u, v;
        scanf("%d %d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for(int i = 1; i <= n; i++) if(G[i].size()==1) sam.bfs(i);
    printf("%lld\n",sam.query());
    return 0;
}

BZOJ3926 [Zjoi2015]诸神眷顾的幻想乡【广义后缀自动机】

原文:https://www.cnblogs.com/kikokiko/p/12718180.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!