Sorted algorithm template collection: ACM template
Click me to see the algorithm family bucket series!!!
It is actually a new refining template integration plan
Problem
Given a point weighted rootless tree, for each k ∈ [ 1 , 2 × 1 0 5 ] k\in[1,2\times10^5] k∈[1,2 × 105], find out how many disordered point pairs there are ( x , y ) (x,y) (x,y) satisfied x x x to y y The point weight of all nodes on the simple path (chain) of y gcd \gcd gcd equals k k k. (point centered) x x x can be equal to y y y. That is, a single point is also counted as an answer)
1 ≤ n , a i ≤ 2 × 1 0 5 1\le n,a_i\le 2\times 10^5 1≤n,ai≤2×105
Input
3 1 2 3 1 2 2 3
Output
1 4 2 1 3 1
Solution
Definition tree gcd ( x , y ) \gcd(x,y) gcd(x,y) represents the slave point x x x to point y y The point weight of all points through which the simple path (chain) between y passes gcd \gcd gcd.
set up a n s = f ( k ) ans=f(k) ans=f(k), where f ( n ) f(n) f(n) indicates all the data on the tree that you want to ask in the title gcd ( x , y ) = n \gcd(x,y)=n GCD (x, y) = point pair of n ( x , y ) (x,y) (x,y). Obviously, it's a little difficult to start, because what we're looking for here is gcd = n \gcd=n gcd=n, it's fixed, which means we need to calculate all the values gcd \gcd gcd, obviously O ( n 2 ) O(n^2) Complexity of O(n2).
The problem on the tree is quite abstract, so we can't list the mathematical formula very succinctly and consider it
gcd
\gcd
The gcd counting problem is tried to be solved directly by Mobius inversion formula. Our constructor
F
(
n
)
=
∑
n
∣
d
f
(
d
)
F(n)=\sum\limits_{n\mid d}f(d)
F(n)=n∣d∑f(d)
obviously
F
(
n
)
F(n)
The actual meaning of F(n) is
n
∣
gcd
(
x
,
y
)
n\mid\gcd(x,y)
Point pairs of n ∣ gcd(x,y)
(
x
,
y
)
(x,y)
The number of (x,y), that is, the number of all simple paths (chains)
gcd
(
x
,
y
)
\gcd(x,y)
There are factors in gcd(x,y)
n
n
The number of point pairs of n.
At this time, according to Mobius inversion formula:
f ( n ) = ∑ n ∣ d F ( d ) μ ( d n ) f(n)=\sum_{n\mid d}F(d)\mu(\dfrac{d}{n}) f(n)=n∣d∑F(d)μ(nd)
So we just need to calculate F ( i ) , i ∈ [ 1 , max { a [ i ] } ] F(i),i\in[1,\max\{a[i]\}] F(i),i ∈ [1,max{a[i]}], and then O ( n l o g n ) O(nlogn) O(nlogn) convolution calculation f ( i ) f(i) f(i) is sufficient. ( gcd ( x , y ) ≤ max ( a [ i ] ) \gcd(x,y)\le \max(a[i]) gcd(x,y)≤max(a[i]))
because F ( n ) F(n) F(n) means the sum of all simple paths (chains) gcd ( x , y ) \gcd(x,y) There are factors in gcd(x,y) n n The number of point pairs of n, so we can calculate the factors of all point weights from the perspective of factors ( x , y ) (x,y) In (x,y) x x x can be equal to y y y. So f (factor) + +, and then build a hierarchical graph for all factors, processing one factor at a time.
For factor x x x. We will n − 1 n-1 n − 1 side ( u , v ) (u,v) All in (u,v) gcd ( a [ u ] , a [ v ] ) \gcd(a[u],a[v]) gcd(a[u],a[v]) contains factors x x The edges of x are constructed into a hierarchical graph, then all edges in the hierarchical graph have factors x x x. In the process of drawing edge connection, for two chains (connecting blocks) A , B A,B A. B. We need to calculate the number of point pairs, so we can maintain the number of points of each connected block with the joint search set. When using the joint search set to connect them, F ( x ) F(x) The new contribution (new point pair) obtained by F(x) is obviously s i z e [ A ] × s i z e [ B ] size[A]\times size[B] size[A]×size[B]( A A Each point in A can be B B Select any point in B to form a new point pair). By performing this process for all factors, we can calculate all the factors F ( i ) F(i) F(i).
Finally, analyze the complexity: 1 ∼ 2 × 1 0 5 1\sim 2\times 10^5 1∼2 × 105 has the most divisors 160 160 160, that is, each edge can be at most 160 160 There are 160 hierarchical graphs. We first decompose the factors of each edge, then construct the hierarchical graph, and then enumerate the hierarchical graph, use and query the set to build the graph. The complexity is O ( n × max { 160 , n } ) O(n\times \max\{160, \sqrt{n}\}) O(n×max{160,n })
Code
// Problem: G. GCD Counting // Contest: Codeforces - Educational Codeforces Round 45 (Rated for Div. 2) // URL: https://codeforces.com/problemset/problem/990/G // Memory Limit: 256 MB // Time Limit: 4500 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 2e5 + 7, M = 2e3 + 7; int n, m, k, t; int a[N]; int primes[N], cnt, mu[N]; bool vis[N]; int fa[N], siz[N]; ll f[N], F[N]; int u[N], v[N]; int maxx; vector <int> c[N]; template <typename T> inline void read(T& t) { int f = 0, c = getchar(); t = 0; while (!isdigit(c)) f |= c == '-', c = getchar(); while (isdigit(c)) t = t * 10 + c - 48, c = getchar(); if (f) t = -t; } template <typename T> void print(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) print(x / 10); putchar(x % 10 + 48); } void init(int n) { vis[1] = 1; mu[1] = 1; for(int i = 1; i <= n; ++ i) { if(vis[i] == 0) { primes[ ++ cnt] = i; mu[i] = -1; } for(int j = 1; j <= cnt && i * primes[j] <= n; ++ j) { vis[i * primes[j]] = 1; if(i % primes[j] == 0) { mu[i * primes[j]] = 0; break; } mu[i * primes[j]] -= mu[i]; } } } int Find(int x) { if(fa[x] == x) return x; return fa[x] = Find(fa[x]); } void Union(int d, int x, int y) { int fx = Find(x); int fy = Find(y); if(fx == fy) return ; F[d] += 1ll * siz[fx] * siz[fy]; fa[fx] = fy; siz[fy] += siz[fx]; } signed main() { init(N - 7); read(n); for(int i = 1; i <= n; ++ i) { read(a[i]); maxx = max(maxx, a[i]); int x = a[i]; for(int j = 1; j * j <= x; ++ j) { if(x % j == 0) { F[j] ++ ; if(j * j != x) F[x / j] ++ ; } } } /*for(int i = 1; i <= 2e5; ++ i) { if(F[i]) cout << F[i] << endl; }*/ for(int i = 1; i <= n - 1; ++ i) { int x, y; read(x), read(y); u[i] = x, v[i] = y; int gcd = __gcd(a[x], a[y]); for(int j = 1; j * j <= gcd; ++ j) { if(gcd % j == 0) { c[j].push_back(i); if(j * j != gcd) c[gcd / j].push_back(i); } } } int limit = 2e5; for(int i = 1; i <= limit; ++ i) { for(int j = 0; j < c[i].size(); ++ j) { fa[u[c[i][j]]] = u[c[i][j]]; siz[u[c[i][j]]] = 1; fa[v[c[i][j]]] = v[c[i][j]]; siz[v[c[i][j]]] = 1; } for(int j = 0; j < c[i].size(); ++ j) { Union(i, u[c[i][j]], v[c[i][j]]); } } for(int i = 1; i <= limit; ++ i) { for(int j = i; j <= limit; j += i) { f[i] += 1ll * F[j] * mu[j / i]; } } for(int i = 1; i <= limit; ++ i) { if(f[i]) { print(i); putchar(' '); print(f[i]); puts(""); } } return 0; }