You are given a tree consisting of ai.

Let's denote the function y(including these two vertices).

For every integer from g(x,y) is equal to this number.

Input

The first line contains one integer (1≤n≤2⋅105).

The second line contains (1≤ai≤2⋅105) — the numbers written on vertices.

Then y. It is guaranteed that these edges form a tree.

Output

For every integer i 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\n",i,ans[i]);
    return 0;
}

 

相关文章:

  • 2022-12-23
  • 2021-08-11
  • 2021-12-23
  • 2022-12-23
  • 2022-01-24
  • 2021-08-09
  • 2021-06-26
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-03-08
  • 2021-11-16
  • 2021-08-10
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案