题意传送门
题意:
n个节点的树,根节点是1。
每个节点有一个权值,第i个节点权值是 。
每个节点到根节点的路径上的点的gcd就是该节点的美好值。
想要使该节点的美好值更大,可以使路径上任意一个节点的权值改为0,也可以选择一个不改。
每个节点都相互独立。
数据范围: , 。
题解:
每个节点开一个set,记录根节点到当前节点的gcd各种可能以及对应的更改次数,更改此时是0或1。
然后当前节点由父节点转移过来,就是把父节点的set遍历一遍,更改一下,存到当前节点中。
因为因子数并不是很多,所以这样是不会超时的,你意识到这点,这道题就完了。
感受:
看了题解后,一发过。
内心毫无波澜,只觉得自己太弱,没有发现是个暴力。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
typedef pair<int , int> pii ;
const int maxn = 2e5 + 5 ;
int n ;
int a[maxn] ;
int num , head[maxn] ;
int ans[maxn] ;
set<pii> s[maxn] ;
struct Edge
{
int v , next ;
} edge[maxn << 1] ;
void add_edge(int u , int v)
{
edge[num].v = v ;
edge[num].next = head[u] ;
head[u] = num ++ ;
}
void dfs(int fa , int u)
{
for(auto x : s[fa])
{
if(x.second == 0)
{
int y = __gcd(x.first , a[u]) ;
s[u].insert(make_pair(y , 0)) ;
ans[u] = max(ans[u] , y) ;
int z = __gcd(x.first , 0) ;
s[u].insert(make_pair(z , 1)) ;
ans[u] = max(ans[u] , z) ;
}
else
{
int y = __gcd(x.first , a[u]) ;
s[u].insert(make_pair(y , 1)) ;
ans[u] = max(ans[u] , y) ;
}
}
for(int i = head[u] ; i != -1 ; i = edge[i].next)
{
int v = edge[i].v ;
if(v == fa) continue ;
dfs(u , v) ;
}
}
int main()
{
scanf("%d" , &n) ;
for(int i = 1 ; i <= n ; i ++) scanf("%d" , &a[i]) ;
num = 0 , memset(head , -1 , sizeof(head)) ;
for(int i = 1 ; i <= n - 1 ; i ++)
{
int x , y ;
scanf("%d%d" , &x , &y) ;
add_edge(x , y) , add_edge(y , x) ;
}
memset(ans , 0 , sizeof(ans)) ;
ans[1] = a[1] ;
s[1].insert(make_pair(a[1] , 0)) ;
s[1].insert(make_pair(0, 1)) ;
for(int i = head[1] ; i != -1 ; i = edge[i].next)
{
int v = edge[i].v ;
dfs(1 , v) ;
}
for(int i = 1 ; i <= n ; i ++) printf("%d " , ans[i]) ;
printf("\n") ;
return 0 ;
}