zoukankan      html  css  js  c++  java
  • 「美团 CodeM 初赛 Round A」最长树链

    题目描述

    Mr. Walker 最近在研究树,尤其是最长树链问题。现在树中的每个点都有一个值,他想在树中找出最长的链,使得这条链上对应点的值的最大公约数不等于1。请求出这条最长的树链的长度。

    输入格式

    第一行一个整数 n,表示点的个数。

    接下来 n−1 行,每行两个整数 x,y 表示 x,y 之间有边。

    数据保证给出的是一棵树。

    接下来一行 n 个整数表示每个点对应的权值 ai​。

    输出格式

    输出一个整数,表示这条树链的长度。

    样例

    样例输入

    4

    1 2

    1 3

    2 4

    6 4 5 2

    样例输出

    3

    数据范围与提示

    n<=10^5,1<= ai<=10^9。

    【题解】

    做这类题一定要记住这句话:

    没有暴力解决不了的题,只有不敢写暴力的人!

    咳咳,所以说,这题的正解正是暴力。

    读完题后,我们不难想到这样一个暴力:枚举每一个质数,权值是这个质数的倍数的节点设为1,最长链的长度就是点权为1的点构成的最长的链。

    如果枚举所有质数,这题就会变成n*n,一定是A不了的,那怎么办呢?方法是这样的。

    每个数最多只有log个不同的质因数,所以只要把所有点权质因数分解,枚举出现的质数就可以了。

    我们枚举完质因数后dfs,因为每个点最多有log个不同的质因数,所以复杂度大概是O(能过)O(nlogn)。

    【题外话】

    这么写有一些小问题,如果质数极大就会T,Loj是能A的(数据真垃圾),但吕神的数据比较优秀,把我卡成了75.

    这题告诉我:永远不要被数据吓到,也永远不要放弃一题,万一打个暴力能A呢?

    下贴本蒟蒻丑陋的代码

    #include<iostream> 
    #include<cstdio>                
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    const int N=100005;
    int n,con,ans=1,h[N],cnt,a[N],p[N],dis[N];
    bool v[N];
    struct 
    {
        int nex,to;
    }e[N<<1];
    
    void dfs(int u,int b,int c) 
    {
        dis[u]=0;
        for(int i=h[u];i;i=e[i].nex) 
            if(e[i].to!=b && a[e[i].to]%c==0) 
            {
                while(a[e[i].to]%c==0) 
                  a[e[i].to]/=c;
                dfs(e[i].to,u,c);
                ans=max(ans,dis[u]+dis[e[i].to]+1);
                dis[u]=max(dis[u],dis[e[i].to]);
            }
        dis[u]++;
    }
    
    void add(int u,int v)
    {
        cnt++;
        e[cnt].nex=h[u];
        e[cnt].to=v;
        h[u]=cnt;
    }
    
    int main() 
    {
        
        scanf("%d",&n);
        for(int i=2;i*i<=300005;i++)
          if(v[i]==0) 
          {
              for(int j=i*i;j<300005;j+=i) v[j]=1;
          }
        for(int i=2;i<=300005;i++)
          if(v[i]==0)
            p[++con]=i;
        for(int i=1;i<n;i++) 
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        for(int i=1;i<=n;i++) 
          scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) 
        {
            int s=a[i];
            for(int j=1;j<=con && p[j]*p[j]<=a[i];j++)
            {
                if(s%p[j]==0) 
                {
                    while(s%p[j]==0) 
                      s/=p[j];
                    dfs(i,0,p[j]);
                }
            }            
            if(s>1) 
              dfs(i,0,s);
            a[i]=1;
        }
        printf("%d",ans);
        return 0;
    }

    oi路漫漫,愿此题解能助你一臂之力......

  • 相关阅读:
    LeetCode:43. Multiply Strings (Medium)
    LeetCode: 50. Pow(x, n)
    Web服务器、Web容器、Application服务器、反向代理服务器的区别与联系
    LeetCode:49. Group Anagrams(Medium)
    Java:String、StringBuffer、StringBuilder
    Java:泛型
    spring项目中web-inf下不能引用页面资源
    css Hack
    a标签的嵌套
    css中的绝对定位与相对定位
  • 原文地址:https://www.cnblogs.com/mxrmxr/p/9703115.html
Copyright © 2011-2022 走看看