Discription

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



震惊,玄学做法竟然跑过了点分治。。。。
很显然,我们可以先求出g是i倍数的点对数ans[i],然后再反演出答案。
求g是i倍数的点对数的时候就调和级数枚举一下倍数,然后并查集一下就ojbk了。。。

虽然这种做法对于随机数据来说非常的强大,但是一遇到精心构造的数据就gg了,这就是窝一开始TLE的原因。。。
比如n个点的点权都是 <=2e5 的约数最多的数,那么上述做法的总运算次数大致是 O((n+m) * div * 反阿科玛函数),就凉凉了。。。

后来我加了一个比较强的剪枝就过了:
当所有点权都是i的倍数的时候,那就不做并查集,而是直接用 C(n+1,2) 减去 >i且是i倍数的J的ans...

感谢出题人不卡之恩2333


#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define pb push_back
const int maxn=200005;

inline int read(){
	int x=0; char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
	return x;
}

void W(ll x){ if(x>=10) W(x/10); putchar(x%10+'0');}

int n,m,hd[maxn],ne[maxn*2],to[maxn*2],num,cnt[maxn];
int siz[maxn],dfn[maxn],dc,p[maxn],a[maxn];
vector<int> pt[maxn];
ll ans[maxn];

inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}

int getf(int x){ return p[x]==x?x:(p[x]=getf(p[x]));}

inline void solve(){
	for(int i=2e5,O;i;i--){
		dc++,O=0;
		
		for(int j=i;j<=2e5;j+=i) O+=cnt[j],ans[i]-=ans[j];
		
		if(O==n){
			ans[i]+=n*(ll)(n+1)>>1;
			continue;
		}
		
		for(int j=i;j<=2e5;j+=i){
			
			for(int l=pt[j].size()-1,now;l>=0;l--){
				now=pt[j][l];
				
				if(dfn[now]!=dc) dfn[now]=dc,p[now]=now,siz[now]=1,ans[i]++;
				
				for(int k=hd[now],fa,fb;k;k=ne[k]) if(dfn[to[k]]==dc){
					fa=getf(now),fb=getf(to[k]);
					
					if(fa!=fb){
						p[fb]=fa,ans[i]+=siz[fa]*(ll)siz[fb];
						siz[fa]+=siz[fb];
					}
				}
			}
		}
	}
}

int main(){
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
	
	n=read();
	for(int i=1;i<=n;i++) a[i]=read(),pt[a[i]].pb(i),cnt[a[i]]++;
	
	int uu,vv;
	for(int i=1;i<n;i++)
	    uu=read(),vv=read(),add(uu,vv),add(vv,uu);
	
	solve();
	
	for(int i=1;i<=2e5;i++) if(ans[i]) W(i),putchar(' '),W(ans[i]),puts("");
	return 0;
}

  

 

相关文章: