[ZJOI2015]诸神眷顾的幻想乡
III.[ZJOI2015]诸神眷顾的幻想乡
假如这棵树是定根的,那么其就可以被看作一棵trie,trie上本质不同子串数可以直接被建立广义SAM解决;但是这棵树不定根,路径可能拐弯,咋办呢?
发现,其保证叶子数量 。这就意味着我们可以将以每个叶子为根所形成的trie并在一起形成一个大trie,此trie的节点数不大于 ,然后对大trie跑SAM即可。时间复杂度 。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
namespace TR{//both for ordinary tree and for trie
vector<int>v[100100];
int cnt=1;
int col[100100],in[100100];
struct Trie{
int ch[10],id;
}t[2000100];
void dfs(int x,int fa,int FA){
if(!t[FA].ch[col[x]])t[FA].ch[col[x]]=++cnt;
for(auto y:v[x])if(y!=fa)dfs(y,x,t[FA].ch[col[x]]);
}
void init(){
for(int i=1;i<=n;i++)scanf("%d",&col[i]);
for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x),in[x]++,in[y]++;
for(int i=1;i<=n;i++)if(in[i]==1)dfs(i,0,1);
}
}
namespace SAM{
int cnt=1;
struct Suffix_Automaton{
int ch[10],len,fa;
}t[4000100];
int Add(int x,int c){
int xx=++cnt;t[xx].len=t[x].len+1;
for(;x&&!t[x].ch[c];x=t[x].fa)t[x].ch[c]=xx;
if(!x){t[xx].fa=1;return xx;}
int y=t[x].ch[c];
if(t[y].len==t[x].len+1){t[xx].fa=y;return xx;}
int yy=++cnt;t[yy]=t[y];
t[yy].len=t[x].len+1;
t[xx].fa=t[y].fa=yy;
for(;x&&t[x].ch[c]==y;x=t[x].fa)t[x].ch[c]=yy;
return xx;
}
queue<int>q;
void build(){
q.push(1);
TR::t[1].id=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<m;i++)if(TR::t[x].ch[i])TR::t[TR::t[x].ch[i]].id=Add(TR::t[x].id,i),q.push(TR::t[x].ch[i]);
}
}
}
using namespace SAM;
ll res;
int main(){
scanf("%d%d",&n,&m);
TR::init();
build();
for(int i=1;i<=cnt;i++)res+=t[i].len-t[t[i].fa].len;
printf("%lld\n",res);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?