LGP3346-[ZJOI2015]诸神眷顾的幻想乡 (GSAM)

LGP3346-[ZJOI2015]诸神眷顾的幻想乡

题意

给定一个\(n\)个节点的树,每个节点有一个权值,保证树的叶子节点不超过\(20\)个,求树上本质不同的路径有多少条。

Sol

从叶子节点为根开始建树,建出树上的广义后缀自动机后,\(\Sigma node[i].len - node[node[i].fa].len\)就是答案。

本质上树上所有路径都会被包含在所有叶子节点为根的树的路径中。

Code(在线)

/*
* @Author: quun
* @Date:   2021-09-24 22:28:36
* @Last Modified by:   quun
* @Last Modified time: 2021-09-24 22:50:16
*/
#include<bits/stdc++.h>
using namespace std;
int last=1,tot=1;
const int N = 1e6+10;
typedef long long ll;

/**
 * GSAM + 在线正版 
 *
 * 求树上本质不同的路径个数
 * 
 */

struct Node{
	int len,fa;
	int ch[10];
}node[N*2];

char s[N];
int n,c;
int idx;
int h[N*2],e[N*3],ne[N*3];

void add(int x,int y){
	e[++idx] = y ,ne[idx] = h[x] ,h[x] = idx;
}

int pos[N];
int val[N];
int ind[N];

int extend(int c,int last){
	if(node[last].ch[c]){
		int p = last,x = node[p].ch[c];
		if(node[p].len + 1 == node[x].len){//特判1
			return x;
		}
		else{//特判2
			int y = ++tot;node[y].len = node[p].len+1;
			for(int i=0;i<=9;++i)node[y].ch[i] = node[x].ch[i];
			while(p&&node[p].ch[c]==x)node[p].ch[c]=y,p=node[p].fa;
			node[y].fa=node[x].fa,node[x].fa=y;
			return y;
		}
	}

	int p = last ,np = last = ++tot;
	node[np].len = node[p].len + 1;
	for(;p && !node[p].ch[c]; p = node[p].fa){
		node[p].ch[c] = np;
	}
	if(!p)node[np].fa = 1;
	else{
		int q = node[p].ch[c];
		if(node[q].len == node[p].len + 1){
			node[np].fa = q;
		}
		else{
			int nq = ++tot;
			node[nq] = node[q];
			node[nq].len = node[p].len+1;
			node[q].fa = node[np].fa = nq;
			for(;p && node[p].ch[c] == q;p = node[p].fa){
				node[p].ch[c] = nq;
			}
		}
	}
	return last;

}

void dfs(int x,int fa,int dep){
	pos[x] = extend(val[x],pos[fa]);

	for(int i = h[x]; i ;i = ne[i]){
		int to = e[i];
		if(to == fa)continue;
		dfs(to,x,dep+1);
	}
}

int main(){
	scanf("%d %d",&n,&c);

	for(int i = 1;i <= n;++i){
		scanf("%d",&val[i]);
	}

	for(int i = 1;i <= n-1;++i){
		int l,r;
		scanf("%d %d",&l,&r);
		add(l,r);
		add(r,l);
		ind[l]++,ind[r]++;
	}

	pos[0] = 1;

	for(int i=1;i<=n;++i){
		if(ind[i] == 1){
			dfs(i,0,1);
		}
	}
	ll ans = 0;
	for(int i=2;i<=tot;++i){
		ans = ans + node[i].len - node[node[i].fa].len;
	}
	printf("%lld\n",ans);

	return 0;
}
posted @ 2021-09-27 00:26  Qquun  阅读(36)  评论(0)    收藏  举报