您的位置:首页 > 其它

Codeforces Round #430 (Div. 2) C. Ilya And The Tree

2017-08-30 11:13 477 查看
题意 : 给你一棵树,一个点的美丽程度定义为根节点到这个节点的所有数的 gcd ,你可以将路径中的一个点删掉,求每个点最大的美丽程度是多少。

题解 : 注意到这个题gcd的递减速度是非常快的,每次有效的 gcd 最小下降 为 1 / 2,所以其收敛的速度是 logn 级别的,并且我们发现祖先节点的美丽程度一定大于其后代的美丽程度,又注意到每个点的美丽程度只与其祖先有关系,这是dfs 序 的天然条件,这样我们就可以dfs暴力枚举删掉哪一个数,不会超过 log 个节点。

坑点 : 如果数据中每个数都相等或者子孙都是祖先的倍数的话 gcd 不会收敛对于这种问题我们可以特殊处理一下就可以了。就像下面这样处理一下就可以了 。 

if (temp == pre) {

        if (pa ==
1) {

            if (a[root] > pre) {

                res[root] =
a[root];

            }

            else
res[root] = pre;

        }

        else
res[root] = pre;

    }

ac 代码 : 
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#define ll long long
using namespace  std;
const int maxn = 2e5 + 10;
int a[maxn] = {0};
vector <int> G[maxn];
vector <int> g[maxn];
vector <int> v;
bool vis[maxn] = {0};
int res[maxn] = {0};
int pos = 0;
int mx = 0;
int cnt = 0;
void dfs1 (int root) {
int k = G[root].size();
for (int i = 0;i < k; ++ i) {
int u = G[root][i];
if (!vis[u]) {
g[root].push_back(u);
vis[u] = 1;
dfs1 (u);
}
}
}
void dfs2 (int pa,int root,int pre) {
int k = g[root].size();
if (!vis[root]){
v.push_back (root);
vis[root] = 1;
}
if (pre == 1) {
if (pa == 1) {
res[root] = a[root];
for (int i = 0;i < k; ++ i) {
int u = g[root][i];
dfs2 (root,u,a[root]);
}
}
else {
res[root] = 1;
for (int i = 0;i < k; ++ i) {
int u = g[root][i];
dfs2 (root,u,1);
}
}
v.pop_back();
return ;
}
int temp = __gcd(a[root],pre);
if (temp == pre) {
if (pa == 1) {
if (a[root] > pre) {
res[root] = a[root];
}
else res[root] = pre;
}
else res[root] = pre;
}
else {
int y = v.size();
int ans = 0;
int sum = 0;
for (int i = 0;i < y; ++ i) {
sum = 0;
for (int j = 0;j < y; ++ j) {
if (j == i) continue;
sum = __gcd(sum,a[v[j]]);
}
ans = max(ans,sum);
}
res[root] = ans;
}
for (int i = 0;i < k; ++ i){
dfs2 (root,g[root][i],res[root]);
}
v.pop_back();
}
int main () {
int n;
scanf ("%d",&n);
for (int i =1 ;i <= n ;++ i) scanf ("%d",a + i);
for (int i = 0;i < n - 1; ++ i) {
int x,y;
scanf ("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
vis[1] = 1;
dfs1 (1);
//    cout << g[2].size() << endl;
res[1] = a[1];
int k = g[1].size();
memset (vis,0,sizeof (vis));
for (int i = 0;i < k; ++ i) {
int u = g[1][i];
vis[1] = 1;
v.push_back (1);
dfs2 (1,u,a[1]);
v.pop_back();
}
for (int i = 1;i <= n; ++ i) {
printf ("%d ",res[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces 数论 思维