T12 树论题解

题目:树论

screenshotnoscaleacfefeb0-f035-4c83-a0d7-a14072a23965

首先观察 f 函数,若 ji 的因数,那么 f(i,j)=\frac{i}{j} 否则 f(i,j)=\frac{i\times f(j,i \ \mathrm{mod} \ j)}{i\ \mathrm{mod} \ j},对于每一个点 i 我们都把他们存在边权更小的边上。

然后使用贪心的思想,对于每一个大于 1 的节点 i,我们需要找到一个节点 j 使得 \frac{f(i,j)+f(j,i)}{2} 最小。

具体的对于每一个 i 我们都连接到他的最大真因子 j,这个时候边权就是 \frac{i}{j} 也就是 i 的最小质因子,有人问为什么一定是连通的,很简单:

  1. 对于素数 i,其一定连接到 1
  2. i 为合数,则对应的 j 一定小于它,也就是说 ji 之前已经连过一条边,归纳可知 (i,j) 这条边一定连接到 1,所以连通。

然后我们可以使用欧拉筛来实现找到每个节点的最小质因子,这里复杂度就是 O(n)

void solve(int n){
    for(int i=2;i<=n;i++){//i是质数
        if(!p[i]){
            p[i]=i;
            pp.push_back(i);
        }
        for(int it:pp){
            if(i*it>n)break;
            p[i*it]=it;//p是i*p的最小质因数
            if(i%it==0)break;//确保每个合数只被其最小质因数筛一次
        }
    }
}

然后就是构造一个最小生成树了,我们把每个大于 1 的节点 i 连接到节点 j=\frac{1}{\mathrm{p}(i)} 上,其中 \mathrm{p}(i) 表示 i 的最小质因子。

伪代码:

    /*输入*/
    solve(n);//预处理最小的质因子
    for(int i=2;i<=n;i++){
        int p_=p[i];//i的最小质因数
        int j=i/p_;//i的最大真因数
        sum+=p_;//边权为 p
        g.push_back({j,i});//添加边(j,i)
    }
    /*输出*/
2 个赞

帮忙搜一下这题的原题,想做

1 个赞

@stringdp100005 没原题,搜不到。

1 个赞

@stringdp100005 你把代码写出来,我帮你测?

1 个赞

算了吧,我还缺一大堆题每补

1 个赞

@stringdp100005 e好的

1 个赞

image

为啥这样最小,如何证明?

image

还有如何证明,这样选边,能选出一个连通的树?

1 个赞

把这道题目搬运了一下,求造数据: 求造数据,悬赏解决方案一个,并且洛谷三关 or 大号互关。 - 常规 - 信友队论坛

1 个赞