zoukankan      html  css  js  c++  java
  • CodeForces990G:GCD Counting(树分治+GCD)

    You are given a tree consisting of nn vertices. A number is written on each vertex; the number on vertex ii is equal to aiai.

    Let's denote the function g(x,y)g(x,y) as the greatest common divisor of the numbers written on the vertices belonging to the simple path from vertex xx to vertex yy(including these two vertices).

    For every integer from 11 to 21052⋅105 you have to count the number of pairs (x,y)(x,y) (1xyn)(1≤x≤y≤n) such that g(x,y)g(x,y) is equal to this number.

    Input

    The first line contains one integer nn — the number of vertices (1n2105)(1≤n≤2⋅105).

    The second line contains nn integers a1a1, a2a2, ..., anan (1ai2105)(1≤ai≤2⋅105) — the numbers written on vertices.

    Then n1n−1 lines follow, each containing two integers xx and y(1x,yn,xy)(1≤x,y≤n,x≠y)denoting an edge connecting vertex xx with vertex yy. It is guaranteed that these edges form a tree.

    Output

    For every integer ii from 11 to 21052⋅105 do the following: if there is no pair (x,y)(x,y) such that xyx≤y and g(x,y)=ig(x,y)=i, don't output anything. Otherwise output two integers: iiand the number of aforementioned pairs. You have to consider the values of ii in ascending order.

    See the examples for better understanding.

    Examples

    Input
    3
    1 2 3
    1 2
    2 3
    Output
    1 4
    2 1
    3 1
    Input
    6
    1 2 4 8 16 32
    1 6
    6 3
    3 4
    4 2
    6 5
    Output
    1 6
    2 5
    4 6
    8 1
    16 2
    32 1
    Input
    4
    9 16 144 6
    1 3
    2 3
    4 3
    Output
    1 1
    2 1
    3 1
    6 2
    9 2
    16 2
    144 1

    题意:求所有简单路径的GCD,统计数量。

    思路:不难想到是分治,问题转化为多个小问题:统计经过某点的路径的GCD,由于GCD具有收敛性,不同GCD的数量级是log级别的,虽然有多个链,但感觉gcd是数量就算不会太多,2333,我猜复杂度不超过O(N*logN*logN*logN)级别吧。所以对于当前子树,每次访问一条链的时候统计这条链和之前所有GCD的gcd。。。。说不清楚,反正一想就会相通的东西。

    具有收敛性的有:GCD,或,且...

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=200010;
    const int inf=0x7FFFFFFF; 
    int Laxt[maxn],Next[maxn<<1],To[maxn<<1],cnt,N,sn;
    int a[maxn],sz[maxn],son[maxn],vis[maxn],root; ll ans[maxn];
    map<int,int>mp,tp;
    map<int,int>::iterator it1,it2;
    inline void read(int &x) {
        x=0; char c=getchar();
        while(c>'9'||c<'0') c=getchar();
        while(c<='9'&&c>='0') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    }
    void add(int u,int v){
        Next[++cnt]=Laxt[u];
        Laxt[u]=cnt; To[cnt]=v;
    }
    void getroot(int u,int fa) //找重心 
    {
        sz[u]=1; son[u]=0;
        for(int i=Laxt[u];i;i=Next[i]){
            if(To[i]!=fa&&!vis[To[i]]){
                getroot(To[i],u);
                sz[u]+=sz[To[i]];
                son[u]=max(son[u],sz[To[i]]);
            }
        }
        son[u]=max(son[u],sn-son[u]);
        if(root==0||son[root]>son[u]) root=u;
    }
    void getans(int u,int fa,int num) //对于当前链产生的新GCD 
    {
        tp[num]++;
        for(int i=Laxt[u];i;i=Next[i]){
            if(!vis[To[i]]&&To[i]!=fa){
                getans(To[i],u,__gcd(num,a[To[i]]));
            }
        }
    }
    void solve(int u) //解决以u为根的子问题 
    {
        mp.clear(); mp[a[u]]++; ans[a[u]]++;
        for(int i=Laxt[u];i;i=Next[i])
          if(!vis[To[i]]) {
             tp.clear(); getans(To[i],u,__gcd(a[u],a[To[i]]));
             for(it1=mp.begin();it1!=mp.end();it1++)
               for(it2=tp.begin();it2!=tp.end();it2++){
                  int g=__gcd((*it1).first,(*it2).first);
                  ans[g]+=(ll)(*it1).second*(*it2).second;
            }
            for(it2=tp.begin();it2!=tp.end();it2++)
              mp[(*it2).first]+=(*it2).second;
        }
    }
    void dfs(int u)  //分治 
    {
        vis[u]=1;  solve(u);
        for(int i=Laxt[u];i;i=Next[i]){
            if(vis[To[i]]) continue;
            root=0; sn=sz[To[i]]; 
            getroot(To[i],0); dfs(root);
        }
    }
    int main()
    {
        read(N); int u,v,Max=0;
        for(int i=1;i<=N;i++) read(a[i]),Max=max(Max,a[i]);
        for(int i=1;i<N;i++) {
            read(u);read(v);
            add(u,v);  add(v,u);
        }
        root=0; sn=N; getroot(1,0); dfs(root);
        for(int i=1;i<=Max;i++) if(ans[i]) printf("%d %I64d
    ",i,ans[i]);
        return 0;
    }
  • 相关阅读:
    挂载nfs网络共享目录到本地目录报错
    ubuntu18.04,centos7.7下安装nfs详细步骤
    linux的fstab配置文件
    nginx整合php后,浏览器访问.php文件报错
    centos中安装php7.3.13(目前最新版)
    skills_nginx
    problems_ubuntu
    problems_nginx
    docker中部署halo
    数论学习
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9184355.html
Copyright © 2011-2022 走看看