hdu6430 - Problem E. TeaTree (启发式合并)

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6430

题目大意:

    给你一棵有n个节点的树,树上的每个节点都有一个值v_i

    让你求对每个节点x,对其 子节点 i 与子节点 j ,其最近公共祖先lca( i, j ) = x 

    而该节点x的答案为 ans[X]=max(gcd(val[i],vaj[j])) , i , j 满足 lca(i,j) = x

题解:

    参考博客:https://blog.csdn.net/lifelikes/article/details/81980619

    因为时第一次接触启发式合并,所以这题我是直接分析上面这位大神的代码的,之后分析如下

    对于一个节点,对其最大的子树的节点信息都已经加入num与divs数组中,之后再将其他比较小的子树的节点信息一一加入两数组,查询出最大gcd。而在返回上层时,如果处理的不是父节点的最大子树,则在将这棵子树的节点信息都删除。

    复杂度分析是O(n^(3/2)*log(n))  其中的n^(1/2)是添加因数时的复杂度

AC代码(带注释):

#include  
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int N = 300010;
struct edge{
	int v,next;
	ll w;
};
//数的因子 
vector fa[N];
//邻接表 
int tot;
int head[N];
edge es[N<<1];
//树的节点个数 节点的最大节点数的子树 
int sz[N],sma[N];

int num[N];	//当前数字出现的次数 
int divs[N];	//当前因子出现的次数 
vector temp;	//子树节点统计的临时数组 

int n;
int val[N];	//节点数字 
int ans[N];

int tmp;

void add(int u,int v)
{
	es[tot].v = v;
	es[tot].next = head[u];
	head[u] = tot;
	tot ++;
}
void dfs1(int u,int pre)
{
	int i;
	sz[u] = 1;
	for(i=head[u];i!=-1;i=es[i].next)
	{
		int v = es[i].v;
		if(v == pre)	continue;
		dfs1(v,u);
		sz[u] += sz[v];
		if(sz[v] > sz[sma[u]])
			sma[u] = v;
	}
}
//增一个数字引起的各种变化 
void add_node(int u)
{
	int cnt,i;
	num[val[u]] ++;
	if(num[val[u]] == 1)
	{
		for(i=0;i

 

你可能感兴趣的:(搜索)