C. Ilya And The Tree(gcd的分析+暴力转移)

题目

题意:

    给定一棵树,每个点都有权值。每个节点的答案等于节点到根的路径上所有点的权值的gcd,对于每个点,都可以使这条路径上的某个点的权值变为0,要求使得每个节点的答案尽可能大。
     1 n 2 1 0 5 , 1 i n , 1 a i 2 1 0 5 1 ≤ n ≤ 2·10^5,1 ≤ i ≤ n, 1 ≤ a_i ≤ 2·10^5

分析:

    因为是gcd,gcd一个很显然的性质就是这些值的种类并不多,本题的关键点就在这里。所以我们可以暴力去计算,对于每个点维护一个set,存放当前节点到根节点路径上删除某个点后剩下的gcd。在搜索的时候维护这个set就可以了,对于当前节点,就从父节点的set数组中取出数来与当前节点的权值取gcd即可,因为只能删除一次,再加上删除当前节点的gcd即可,这个gcd就递归的时候下传。

#include <iostream>
#include <vector>
#include <set> 
using namespace std;

vector<int> g[200005];
set<int> res[200005];
int dp[200005][2],v[200005];

int _gcd(int a,int b)
{
	if( b == 0 ) return a;
	return _gcd(b,a%b);
} 

void dfs(int x,int fa,int gcd)
{
	for (int i = 0; i < g[x].size(); i++)
	{
		int t = g[x][i];
		if( t == fa ) continue;
		set<int>:: iterator it;
		res[t].insert(gcd);
		for (it = res[x].begin(); it != res[x].end(); it++)
		{
			res[t].insert(_gcd(*it,v[t]));
		}
		dfs(t,x,_gcd(gcd,v[t]));
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> v[i];
	}
	for (int i = 1; i < n; i++)
	{
		int x,y;
		cin >> x >> y;
		g[x].push_back(y);
		g[y].push_back(x);  
	}
	dp[1][0] = v[1];
	dp[1][1] = 0;
	res[1].insert(0);
	dfs(1,0,v[1]);
	for (int i = 1; i <= n; i++)
	{
		if( i == 1 ) cout << v[i];
		else cout << *--res[i].end();
		if( i == n ) cout << '\n';
		else cout << ' ';
	}
	return 0;
}

发布了132 篇原创文章 · 获赞 6 · 访问量 7908

猜你喜欢

转载自blog.csdn.net/weixin_44316314/article/details/105137331