bzoj3926: [Zjoi2015]诸神眷顾的幻想乡

因为叶子只有20个,那么对于每个叶子节点当作根建一棵trie,然后一条路径是某一个trie上的一条上到下的路径

然后......广义sam sb题

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;

struct node
{
    int x,y,next;
}a[210000];int len,last[110000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
int lf[30];
void findleaf(int x,int fr)
{
    int t=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fr)
        {
            t++;
            findleaf(y,x);
        }
    }
    if(t==0|(x==1&&t==1))lf[++lf[0]]=x;
}

//---------------------------------init:findleaf-----------------------------------------------------

int col[110000];
struct Trie
{
    int w[15],col;
    void init(int COL){memset(w,0,sizeof(w));col=COL;}
}tr[2100000];int trlen;
int Trie_insert(int x,int now)
{
    if(tr[now].w[x]==0)
        tr[now].w[x]=++trlen, tr[trlen].init(x);
    return tr[now].w[x];
}

int fr[2100000],pos[2100000];
int head,tail,list[2100000];
void Trie_merge(int rt)
{
    fr[rt]=0,pos[0]=0;
    head=1,tail=2;list[1]=rt;
    while(head!=tail)
    {
        int x=list[head]; pos[x]=Trie_insert(col[x],pos[fr[x]]);
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fr[x])
            {
                fr[y]=x;
                list[tail++]=y;
            }
        }
        fr[x]=0;
        head++;
    }
}
void Trie_main()
{
    trlen=0;
    for(int i=1;i<=lf[0];i++)Trie_merge(lf[i]);
}

//---------------------------------------maketrie---------------------------------------------------

struct SAM
{
    int w[15],dep,fail;
}ch[4100000];int cnt;
int SAM_insert(int pre,int x)
{
    int now=++cnt;
    ch[now].dep=ch[pre].dep+1;
    
    while(pre!=0&&ch[pre].w[x]==0)
        ch[pre].w[x]=now, pre=ch[pre].fail;
        
    if(pre==0)ch[now].fail=1;
    else
    {
        int nxt=ch[pre].w[x];
        if(ch[nxt].dep==ch[pre].dep+1)ch[now].fail=nxt;
        else
        {
            int nnxt=++cnt;
            ch[nnxt]=ch[nxt];
            ch[nnxt].dep=ch[pre].dep+1;
            
            ch[nxt].fail=ch[now].fail=nnxt;
            while(pre!=0&&ch[pre].w[x]==nxt)
                ch[pre].w[x]=nnxt, pre=ch[pre].fail;
        }
    }
    return now;
}

int C;
void SAM_main()
{
    cnt=1;
    head=1,tail=1;
    pos[0]=1;
    for(int x=1;x<=C;x++)
        if(tr[0].w[x]!=0) fr[tr[0].w[x]]=0, list[tail++]=tr[0].w[x];
    while(head!=tail)
    {
        int now=list[head]; pos[now]=SAM_insert(pos[fr[now]],tr[now].col);
        for(int x=1;x<=C;x++)
            if(tr[now].w[x]!=0)
            {
                fr[tr[now].w[x]]=now;
                list[tail++]=tr[now].w[x];
            }
        head++;
    }
}

//---------------------------------------makeSAM----------------------------------------------------

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,x,y;
    scanf("%d%d",&n,&C);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=n;i++)scanf("%d",&col[i]),col[i]++;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        ins(x,y),ins(y,x);
    }
    findleaf(1,0);
    
    Trie_main();
    SAM_main();
    
    LL ans=0;
    for(int i=2;i<=cnt;i++)
        ans+=ch[i].dep-ch[ch[i].fail].dep;
    printf("%lld\n",ans);
    
    return 0;
}

 

posted @ 2018-12-03 13:51  AKCqhzdy  阅读(145)  评论(0编辑  收藏  举报