转自:https://blog.youkuaiyun.com/my_sunshine26/article/details/77696662
题意:给出一棵生成树,每个节点都有一个值,现在要求出每个节点的美丽值的最大值,美丽值的定义为从根节点到该节点(包含)路径上所有点的值的gcd,求解每个点时可以把路径上某一个点的值变为0。你可以认为每个点美丽值的求解是独立的。
思路:
显然,我们可以进行树上DFS。
我们用dp数组来保存每个节点在路径上没有改变值的时候的gcd,然后先单独考虑当前点不选的美丽值即dp[u]。然后用vector[u]数组来保存节点v的父亲节点的美丽值的所有可能情况,这里的情况有可能是改变了值后的,也可能没有,但由于我们在这一步一定会算入节点v的值(不算的情况单独考虑),所以满足最多只改变一次值的要求。
每次更新完后去重一下,提高时间效率以及避免超内存等等。
不去重的话会超内存
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
typedef long long ll;
const int maxn = 200005;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int n,cnt;
int a[maxn],dp[maxn];
int head[maxn];
vector<int>vec[maxn];
struct node
{
int v,next;
}e[maxn*2];
void add(int u,int v)
{
e[cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int pre)
{
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(v==pre) continue;
dp[v]=gcd(dp[u],a[v]);
vec[v].push_back(dp[u]); //不改变当前节点值的情况
for(int i=0;i<vec[u].size();i++)
{
vec[v].push_back(gcd(vec[u][i],a[v]));
}
sort(vec[v].begin(),vec[v].end()); //排序去重
vec[v].erase(unique(vec[v].begin(),vec[v].end()),vec[v].end());
dfs(v,u);
}
}
int main()
{
mst(head,-1);
cnt=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int x,y;
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dp[1]=a[1];
vec[1].push_back(0);
dfs(1,-1);
for(int i=1;i<=n;i++)
{
dp[i]=max(dp[i],vec[i].back()); //后者取数组里的最大值
}
for(int i=1;i<n;i++)
{
printf("%d ",dp[i]);
}
printf("%d\n",dp[n]);
}