Codeforces 842C Ilya And The Tree

来源:互联网 发布:mac怎么设置虚拟打印机 编辑:程序博客网 时间:2024/06/07 03:02

Codeforces 842C Ilya And The Tree

树上gcd

题目

有一棵根节点为1的树,每个结点都有权值。求每个结点从根节点到它的路径上的点的最大gcd(最多可以把一个路径上的一个点权值变成0)。

思路

关于区间gcd。。有个结论:就是可以‘暴力’,因为区间gcd收敛非常快,无论是在线段树搞,还是这次这题。都是暴力。线段树处理区间gcd的一题

开始写树形dp,dp开两个记录当前节点的路径最大gcd,dp[u][0]表示不删节点,dp[u][1]表示删除当前节点。果断WA。因为比如一条路是5,6,10,扫到6时,最大gcd是去掉5,得6,但是扫到10时,只能从6转移过来,认为区间gcd是1。说到底是dp记录的信息不够,不能获得父亲所有可能的gcd的情况。

因为区间gcd收敛很快,所以我们开n个vector,记录每个节点可能的gcd情况,暴力的转移。为了优化时间,每个节点的gcd情况要排序并去重。

%%%

由于一个数的因子个数为松散的n,而且一条路径上的gcd会很快的将到1。所以如果我们从根节点往下dfs,记录所有可以通过把1个或0个点权值变成0得到的gcd。对于每个点,答案就是转移到当前点的所有gcd的最大值。
时间复杂度为O(V∗d),其中V为顶点数,d为因子数。

代码

VS2015跑会在去重那块RE,提示越界。不知道为什么,gcc是能过的。
这里写图片描述

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<iostream>#define M(a,b) memset(a,b,sizeof(a))#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1using namespace std;const int MAXN=200007;typedef long long LL;struct Edge{    int to, ne;}e[MAXN<<1];int head[MAXN], v[MAXN], edgenum;inline void addedge(int u, int v){    edgenum++;e[edgenum].to=v, e[edgenum].ne=head[u], head[u]=edgenum;    edgenum++;e[edgenum].to=u, e[edgenum].ne=head[v], head[v]=edgenum;}vector<int> dp[MAXN];int fgcd[MAXN];int gcd(int a, int b) { return b==0 ? a : gcd(b, a%b); }void dfs(int u, int fa){    if(fa==-1)    {        fgcd[u]=v[u];        dp[u].push_back(0);        dp[u].push_back(v[u]);    }    else    {        fgcd[u]=gcd(fgcd[fa], v[u]);        dp[u].push_back(fgcd[fa]);        for(int i=0;i<dp[fa].size();i++)            dp[u].push_back(gcd(dp[fa][i], v[u]));        sort(dp[u].begin(), dp[u].end());        dp[u].erase(unique(dp[u].begin(), dp[u].end()), dp[u].end());    }    for(int i=head[u]; ~i;i=e[i].ne)        if(e[i].to!=fa)            dfs(e[i].to, u);}int main(){    int n;    while(cin>>n)    {        for(int i=1;i<=n;i++)            scanf("%d", &v[i]);        M(head, -1);edgenum=0;M(dp, 0);        for(int i=1;i<n;i++)        {            int u, v;cin>>u>>v;            addedge(u, v);        }        for(int i=1;i<=n;i++) dp[i].clear();        dfs(1, -1);        for(int i=1;i<=n;i++)            printf("%d%c", dp[i][dp[i].size()-1], i==n ? '\n' : ' ');    }}
阅读全文
0 0
原创粉丝点击