[CodeForeces842]Ilya And The Tree解题报告(因数分解)

传送门:不要戳我QAQ
 
这道题是昨天晚上模拟赛的第二题。一下子没冷静就写了一坨树剖,没调出来,最后交一个n3的暴力然后爆零了。
考虑到每个节点的最后答案都是从这个节点到根节点的一条链,并且每个节点都要有答案。所以不应该考虑树链剖分而应该考虑树形dp。
每个节点最后的答案链都必然交与根节点,这意味着我们的答案有两种情况:取了根节点和没取根节点。没取根节点的情况很好维护,用普通的dfs就搞定了,这里不细解释,不明白看代码就懂了。
对于取根节点的情况,我们这样考虑,既然取了根节点,那么最后答案必然是根节点权值的因子,因为gcd的第一个数就是根节点的权值。我们维护一个数组num[x],表示我们做树形dp的dfs时,当前结点到根节点的路径上所有节点包含的根节点的因子的个数。简单点说就是,根节点的因子在路上出现的次数。对于一个节点,如果它要取一个答案x,那么x必须满足两个条件,1,该节点权值被x整除,2,x在该节点到根的路上出现了至少depth-1(该节点深度)次。(depth-1)次就能做到去掉一个节点后该值能整除所有节点。
那么代码实现就很简单了。
我的代码的分解因子部分写丑了,但因为AC了,就懒地该成sqrt(N)的形式,大家不要学我qwq。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 500005
using namespace std;
inline void read(int &x)
{
    x=0;int f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
int gcd(int a,int b)
{
    if(a==0)
        return b;
    if(b==0)
        return a;
    return gcd(b,a%b);
}
struct node{
    int nex,to;
}edge[maxn];
int head[maxn],tot;
int N,a[maxn];
inline void insert(int from,int to)
{
    edge[++tot].nex=head[from];
    edge[tot].to=to;
    head[from]=tot;
}
int dp_nroot[maxn],dp_all[maxn],dp_root[maxn],ans[maxn];
int p[maxn],id,num[maxn];
void init()
{
    int n=a[1]/2;
    for(int i=2;i<=n;i++)
        if(a[1]%i==0)
            p[++id]=i;
    p[++id]=a[1];
}
int dept[maxn];
void dfs(int x,int u)
{
    dept[x]=dept[u]+1;
    if(x!=1)
        dp_nroot[x]=gcd(dp_nroot[u],a[x]);
    dp_all[x]=gcd(dp_all[u],a[x]);
    for(int i=1;i<=id;i++)
        if(a[x]%p[i]==0)
            num[i]++;
    /*cout<<"NOTE :"<<x<<endl;
    for(int i=1;i<=id;i++)
        cout<<num[i]<<" ";
    cout<<endl;*/
    for(int i=id;i>0;i--)
        if(num[i]>=dept[x]-1)
        {
            dp_root[x]=p[i];
            //cout<<"ROOT NTOE: "<<x<<" "<<p[i]<<endl;
            break;
        }
            
    ans[x]=max(dp_root[x],max(dp_nroot[x],dp_all[x]));
    for(int i=head[x];i;i=edge[i].nex)
        if(edge[i].to^u)    
            dfs(edge[i].to,x);
    for(int i=1;i<=id;i++)
        if(a[x]%p[i]==0)
            num[i]--;
}
int main()
{
    read(N);
    int u,v;
    for(int i=1;i<=N;i++)
        read(a[i]);
    for(int i=1;i<N;i++)
    {
        read(u);
        read(v);
        insert(u,v);
        insert(v,u);
    }
    init();
    //for(int i=1;i<=id;i++)
    //    cout<<p[i]<<" ";
    //cout<<endl;
    dfs(1,1);
    /*for(int i=1;i<=N;i++)
        cout<<dp_all[i]<<" "<<dp_nroot[i]<<" "<<dp_root[i]<<endl;*/
    for(int i=1;i<=N;i++)
        printf("%d ",ans[i]);
}

 

 
 
posted @ 2018-09-14 16:25  溡沭  阅读(181)  评论(1编辑  收藏  举报