• 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;
    }
  • 相关阅读:
    Conference deadlines
    waiting list
    BDA3 Chapter 1 Probability and inference
    PP: Articial Intelligence—TheRevolution Hasn’t HappenedYet
    兼容ie9文件上传,及现代浏览器实现进度条
    input 打开文件夹事件委托
    前端构建工具gulpjs的使用介绍及技巧
    如何编写兼容各主流邮箱的HTML邮件
    前端通用框架可行性研究报告之弹窗
    切换tab键,不聚焦a标签
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9184355.html
Copyright © 2020-2023  润新知