1. 程式人生 > >[ZJOI2015]諸神眷顧的幻想鄉

[ZJOI2015]諸神眷顧的幻想鄉

傳送門

這題的字串匹配搬到了樹上……?那不在一條鏈咋做啊……不會了,涼涼……

然後麗潔姐姐給我們留了一條生路……就是保證了葉子節點的個數不超過20.

樹上任意一條路徑,我們總能找到一個葉子節點,使得以它為根的時候這條路徑在一條鏈上。那我們可以把每個葉子節點作為根節點來建立廣義字尾自動機,最後直接統計一下不同子串數量就行了。

不過咋建立啊……不會了,涼涼……

建立方法就是找樹上度數為1的點,之後從SAM的根開始建立,這裡有一些不同的是,我們需要返回一下當前的新節點編號,因為我們在樹上遍歷的時候,只知道你要插入的字元,不知道你要往哪插……然後我們就這樣遍歷這棵樹,插入對應字元即可。

最後統計一下不同的子串數量。因為這題是本質不同的個數,所以直接遍歷所有節點,答案加上\(l[i] - l[fa[i]]\)

即可。

看一下程式碼。

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 2000005;
const ll INF = 5e18;

int read()
{
   int ans = 0,op = 1;char ch = getchar();
   while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
   while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
   return ans * op;
}

int s[M],head[N],ecnt,n,c,x,y,deg[N];
ll ans;

struct edge
{
    int next,to,from;
}e[N<<1];

struct Suffix
{
    int cnt,ch[N][15],fa[N],l[N];
    int extend(int p,int c)
    {
        int np = ++cnt;
        l[np] = l[p] + 1;
        while(p && !ch[p][c]) ch[p][c] = np,p = fa[p];
        if(!p) {fa[np] = 1;return np;}
        int q = ch[p][c];
        if(l[q] == l[p] + 1) fa[np] = q;
        else
        {
            int nq = ++cnt;
            l[nq] = l[p] + 1,memcpy(ch[nq],ch[q],sizeof(ch[q]));
            fa[nq] = fa[q],fa[q] = fa[np] = nq;
            while(ch[p][c] == q) ch[p][c] = nq,p = fa[p];
        }
        return np;
    }
    void cal()
    {
        rep(i,2,cnt) ans += l[i] - l[fa[i]];
        printf("%lld\n",ans);
    }
}SAM;

void add(int x,int y)
{
    e[++ecnt] = (edge){head[x],y,x};
    head[x] = ecnt;
}

void dfs(int x,int fa,int g)
{
    g = SAM.extend(g,s[x]);
    for(int i = head[x];i;i = e[i].next) if(e[i].to != fa) dfs(e[i].to,x,g);
}

int main()
{
    n = read(),c = read(),SAM.cnt = 1;
    rep(i,1,n) s[i] = read();
    rep(i,1,n-1) x = read(),y = read(),add(x,y),add(y,x),deg[x]++,deg[y]++;
    rep(i,1,n) if(deg[i] == 1) dfs(i,0,1);
    SAM.cal();
    return 0;
}