正题
题目链接:https://www.luogu.com.cn/problem/P3346
题目大意
一棵树,求树上所有路径构成的字符串有多少种。(叶子不超过303030个)
解题思路
如果是根节点到一些节点的路径的话很好做,直接建广义SAMSAMSAM即可,但是因为路径会拐弯所以我们考虑如何统计拐弯的路径。
不难发现如果选择另一个叶子作为根那么就能让某些拐弯的路径变直,在每个叶子节点处都跑一遍建立广义SAMSAMSAM即可。
时间复杂度O(30n)O(30n)O(30n)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10,M=3e6+10;;
struct node{ll to,next;
}a[N*2];
ll n,m,tot,ans,w[N],ls[N],in[N];
ll cnt,len[M],fa[M],ch[M][10];
ll Ins(ll c,ll p){if(ch[p][c]){ll q=ch[p][c];if(len[p]+1==len[q])return q;else{ll nq=++cnt;len[nq]=len[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[nq]));fa[nq]=fa[q];fa[q]=nq;for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;return nq;}}ll np=++cnt;len[np]=len[p]+1;for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;if(!p)fa[np]=1;else{ll q=ch[p][c];if(len[p]+1==len[q])fa[np]=q;else{ll nq=++cnt;len[nq]=len[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[nq]));fa[nq]=fa[q];fa[np]=fa[q]=nq;for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;}}return np;
}
void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;in[y]++;return;
}
void dfs(ll x,ll fa,ll last){ll tmp=Ins(w[x],last);for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;dfs(y,x,tmp);}return;
}
int main()
{scanf("%lld%lld",&n,&m);cnt=1;for(ll i=1;i<=n;i++)scanf("%lld",&w[i]);for(ll i=1;i<n;i++){ll x,y;scanf("%lld%lld",&x,&y);addl(x,y);addl(y,x);}for(ll i=1;i<=n;i++)if(in[i]==1)dfs(i,0,1);for(ll i=1;i<=cnt;i++)ans+=len[i]-len[fa[i]];printf("%lld",ans);
}