CF990G GCD Counting(树上莫比乌斯反演,分层图,并查集)

Posted 繁凡さん

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF990G GCD Counting(树上莫比乌斯反演,分层图,并查集)相关的知识,希望对你有一定的参考价值。

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


Problem

给定一棵点带权无根树,对于每个 k ∈ [ 1 , 2 × 1 0 5 ] k\\in[1,2\\times10^5] k[1,2×105],求出有多少个无序点对 ( x , y ) (x,y) (x,y) 满足 x x x y y y 的简单路径(链)上的所有节点的点权的 gcd ⁡ \\gcd gcd 等于 k k k。(点对中的 x x x 可以等于 y y y,即单点也算作一个答案)

1 ≤ n , a i ≤ 2 × 1 0 5 1\\le n,a_i\\le 2\\times 10^5 1n,ai2×105

Input

3
1 2 3
1 2
2 3

Output

1 4
2 1
3 1

Solution

定义树上 gcd ⁡ ( x , y ) \\gcd(x,y) gcd(x,y) 表示 从点 x x x 到点 y y y 之间的简单路径(链)经过的所有点的点权的 gcd ⁡ \\gcd gcd

a n s = f ( k ) ans=f(k) ans=f(k) ,其中 f ( n ) f(n) f(n) 表示题目中想要求的树上所有 gcd ⁡ ( x , y ) = n \\gcd(x,y)=n gcd(x,y)=n 的点对 ( x , y ) (x,y) (x,y) 的数量。显然有些难以下手,因为这里求的是 gcd ⁡ = n \\gcd=n gcd=n,已经固定了,也就是说我们需要算出所有的 gcd ⁡ \\gcd gcd,显然是 O ( n 2 ) O(n^2) O(n2) 的复杂度。

树上问题比较抽象,不能很简练的列举出数学公式,考虑 gcd ⁡ \\gcd gcd 计数问题尝试直接使用莫比乌斯反演公式解决。我们构造函数 F ( n ) = ∑ n ∣ d f ( d ) F(n)=\\sum\\limits_{n\\mid d}f(d) F(n)=ndf(d)
显然 F ( n ) F(n) F(n) 的实际含义为 n ∣ gcd ⁡ ( x , y ) n\\mid\\gcd(x,y) ngcd(x,y) 的点对 ( x , y ) (x,y) (x,y) 的数量,即所有简单路径(链)的 gcd ⁡ ( x , y ) \\gcd(x,y) gcd(x,y) 中有因子 n n n 的点对的数量。

此时根据莫比乌斯反演公式有:

f ( n ) = ∑ n ∣ d F ( d ) μ ( d n ) f(n)=\\sum_{n\\mid d}F(d)\\mu(\\dfrac{d}{n}) f(n)=ndF(d)μ(nd)

因此我们只需要计算 F ( i ) , i ∈ [ 1 , max ⁡ { a [ i ] } ] F(i),i\\in[1,\\max\\{a[i]\\}] F(i),i[1,max{a[i]}] ,然后 O ( n l o g n ) O(nlogn) O(nlogn) 卷积计算 f ( i ) f(i) f(i) 即可。( gcd ⁡ ( x , y ) ≤ max ⁡ ( a [ i ] ) \\gcd(x,y)\\le \\max(a[i]) gcd(x,y)max(a[i])

因为 F ( n ) F(n) F(n) 的含义为所有简单路径(链)的 gcd ⁡ ( x , y ) \\gcd(x,y) gcd(x,y) 中有因子 n n n 的点对的数量,所以我们可以从因子的角度出发,求出所有点权的因子,因为点对 ( x , y ) (x,y) (x,y) x x x 可以等于 y y y,所以 F(因子)++ ,然后对于所有的因子建分层图,每次处理一个因子。

对于因子 x x x,我们将 n − 1 n-1 n1 条边 ( u , v ) (u,v) (u,v) 中所有 gcd ⁡ ( a [ u ] , a [ v ] ) \\gcd(a[u],a[v]) gcd(a[u],a[v]) 含有因子 x x x 的边一起构建成一个分层图里,则该分层图中的所有边均有因子 x x x,在建图连边的过程中,对于两条链(连通块) A , B A,B A,B,我们需要计算有多少个点对,所以可以用并查集维护每个连通块的点的个数 size,使用并查集将他们连起来的时候, F ( x ) F(x) F(x) 得到的新的贡献(新的点对)显然为 s i z e [ A ] × s i z e [ B ] size[A]\\times size[B] size[A]×size[B] A A A 中每一个点均可在 B B B 中任意选择一个点凑成一个新的点对)。对于所有因子执行这一过程,我们就可以计算出所有的 F ( i ) F(i) F(i)

最后分析一下复杂度: 1 ∼ 2 × 1 0 5 1\\sim 2\\times 10^5 12×105 中约数最多仅有 160 160 160 个,即每条边最多会在 160 160 160 个分层图里出现,我们先对每条边分解因子然后构建分层图,然后再枚举分层图使用并查集建图,复杂度为 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(以上是关于CF990G GCD Counting(树上莫比乌斯反演,分层图,并查集)的主要内容,如果未能解决你的问题,请参考以下文章

CF EDU 1101D GCD Counting 树形DP + 质因子分解

CF1101D GCD Counting

CF1101D GCD Counting 点分治+质因数分解

CF900DUnusual Sequences 容斥(莫比乌斯反演)

CF990G

Codeforces 990G