[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;
}
posted @ 2019-01-12 22:15  CaptainLi  阅读(105)  评论(0编辑  收藏  举报