[dsu on tree]树上启发式合并总结(算法思想及模板附例题练习)

文章目录

  • 前言
  • 树上启发式合并
    • 引入
    • 算法思想
    • 时间复杂度
  • 模板
  • 练习
    • 例题:CF600E Lomsat gelral
      • solution
      • code
    • CF208E Blood Cousins
      • solution
      • code
    • CF570D Tree Requests
      • solution
      • code
    • CF1009F Dominant Indices
      • solution
      • code

前言

最近不是在⛏李超树嘛,然后就去玩了下线段树,顺道碰见了线段树合并,想起了线段树分治,发现自己连点分治都不会,于是多管齐下,先把树上启发式合并⛏明白再说
在这里插入图片描述

树上启发式合并

引入

说到启发式合并,我们最先想到的是什么??
在这里插入图片描述————就是并查集

普通版

void makeSet( int n ) {for( int i = 1;i <= n;i ++ ) f[i] = i; 
}int find( int x ) {return ( f[x] == x ) ? x : f[x] = find( f[x] );
}void unionSet( int u, int v ) {int fu = f[u], fv = f[v];f[fv] = fu;
}

并查集按秩合并
对于两个大小不一样的集合,将大小 小的并到大的
这个集合的大小可以认为是集合的高度(在正常情况下)
而我们将集合高度小的并到高度大的有助于我们找到父亲
让高度小的树成为高度较大的树的子树,这个优化可以称为启发式合并算法

void makeSet( int n ) {for( int i = 1;i <= n;i ++ ) f[i] = i, siz[i] = 1; 
}int find( int x ) {return ( f[x] == x ) ? x : f[x] = find( f[x] );
}void unionSet( int u, int v ) {int fu = f[u], fv = f[v];if( fu == fv ) return;if( siz[fu] < siz[fv] ) swap( fu, fv );f[fv] = fu, siz[fu] += siz[fv];
}

而我们现在即将要见到的神秘加冰也是启发式合并的一类——树上启发式合并!!
树上启发式合并又叫dsuontreedsu\ on\ treedsu on tree

算法思想

首先发生地点是在树上
在这里插入图片描述
用一道例题将思想由抽象化为具象讲解
在这里插入图片描述
其他AC算法直接踹飞,不考虑哈

人最原始的欲望就是性和杀戮

最暴力的算法就是直接硬刚,对每一个点都暴力搞子树里面所有的点——O(n2)O(n^2)O(n2)
然后就可以成功TTT
在这里插入图片描述

我们考虑暴力算法的时间复杂度为什么会这么高,究竟是卡在哪里了??

树的遍历肯定是建立在dfsdfsdfs上的 你难不成搞bfs 看图👇
在这里插入图片描述
暴力的想法很简单——碰到一个点,就暴算此点的答案
那么这个实现应该是从下往上计算的
当我们遍历到uuu的时候,继续去弄son1son1son1
假设已经搞定了son1son1son1子树所有点,接着就马不停蹄地去搞son2son2son2,同理到son3son3son3
最后再来一遍uuu

发现某些节点啊,总是加了删,删了加 工具人石锤
因为uuu各个儿子之间是彼此独立的,相互之间的答案是不造成干扰的
而这些加删操作时间复杂度就是该子树大小
在这里插入图片描述这不上天谁上天??非常恐怖兄嘚

那怎么办呢?
在这里插入图片描述
暴力这个概念的存在就是为了和优化形成对应
在这个基础上,树上启发式合并的思想就成功诞生了!!

算法思想

  1. 首先O(n)O(n)O(n)遍历一遍树,求出每个点的重儿子——没错就是树链剖分的那个意思
  2. 然后就可以开始搞答案了
    2-1 先把uuu点所有子树的答案都计算完了,再计算uuu——自下而上
    2-2 轻儿子的所有贡献都要删掉——各自独立
    2-3 重儿子的贡献不删掉
    因此,2-2,2-3决定了算法计算有一定的顺序先轻儿子再重儿子

看似只是换了个计算顺序,只是有一个儿子没有暴力操作,其它的跟暴力完全一样啊
但是这样就将时间复杂度变成了O(nlogn)O(nlogn)O(nlogn)
在这里插入图片描述

时间复杂度

像树链剖分一样定义轻边重边轻链重链轻儿子重儿子
红边表示重边,黑边表示轻边,黄点表示该点身份是父亲的重儿子
在这里插入图片描述
因为重儿子的sizesizesize一定≥\ge轻儿子的sizesizesize
所以父亲的sizesizesize一定≥\ge轻儿子sizesizesize的两倍
也就是说,每往上一层,新的父亲的sizesizesize至少是前一层的两倍
等价于,可以说一个点到根节点的路径,不会有超过lognlog\ nlog n条轻边

又因为树上启发式合并的操作,重儿子的子树是不会有倒退操作的,只有轻儿子的子树才会
所以,一个点xxx被遍历操作的次数取决于他到根节点路径上的轻边数+1
ps: +1+1+1是因为他本身要被遍历到

按最极限的最坏(每个点被遍历的次数尽量多) 情况考虑

一个节点的被遍历次数也大约只为=logn+1=logn+1=logn+1
总时间复杂度则为O(n(logn+1))=O(nlogn)O(n(logn+1))=O(nlogn)O(n(logn+1))=O(nlogn)

模板

还是意思意思,给一个并没有什么卵用的模板吧
在这里插入图片描述

void dfs1( int u, int fa ) { //遍历整个树,找每个点的重儿子siz[u] = 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;dfs1( v, u );siz[u] += siz[v];if( ! son[u] || siz[v] > siz[son[u]] )son[u] = v;}
}void modify( int u, int fa, bool flag ) {//flag=0回退 flag=1添加 if( flag ) {//搞一搞}	else {//搞一搞}for( int i = 0;i < G[u].size();i ++ )if( G[u][i] != fa ) modify( G[u][i], u, flag );
}void dfs2( int u, int fa ) {for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa || v == son[u] ) continue;dfs2( v, u );//先算轻儿子的答案modify( v, u, 0 );//计算完轻儿子的答案后 要把儿子的痕迹擦干净 为下一个儿子准备//...可能还有其他的操作}if( son[u] ) dfs2( son[u], u );//重儿子的贡献仍然保留 不回退for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa || v == son[u] ) continue;else modify( v, u, 1 );//开始重新添加每个轻儿子的贡献 为后面计算自己准备}//...一堆操作
}

有等价写法,下面练习的代码基本上是用的这一种
在这里插入图片描述

void dfs1( int u, int fa ) {siz[u] = 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;dfs1( v, u ), siz[u] += siz[v];if( siz[v] > siz[son[u]] || ! son[u] )son[u] = v;}
}void modify( int u, int fa, int k ) {//操作一下for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa || vis[v] ) continue;modify( v, u, k );}
}void dfs2( int u, int fa, int type ) {for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa || v == son[u] ) continue;dfs2( v, u, 0 );//此时先不着急}if( son[u] ) dfs2( son[u], u, 1 ), vis[son[u]] = 1;modify( u, fa, 1 );//把所有轻儿子的贡献统计上//操作if( son[u] ) vis[son[u]] = 0;if( ! type ) modify( u, fa, -1 );//在这里直接遍历整棵树开始回退 因此需要特别对重儿子打个标记
}

练习

在这里插入图片描述

例题:CF600E Lomsat gelral

solution

就是前面用来举例子的题,比较板,可能读题会有所误会
num[i]num[i]num[i]:颜色iii出现的次数
cntcntcnt:颜色出现最多的次数
ansansans:颜色出现次数最多的所有颜色的和
然后直接搞就可以了,具体可见代码

code

#include <cstdio>
#include <vector>
using namespace std;
#define maxn 100005
#define int long long
vector < int > G[maxn];
int n, cnt, ans;
int c[maxn], son[maxn], siz[maxn], num[maxn], result[maxn];void dfs1( int u, int fa ) {siz[u] = 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;dfs1( v, u );siz[u] += siz[v];if( ! son[u] || siz[v] > siz[son[u]] )son[u] = v;}
}void modify( int u, int fa, bool flag ) {//0回退 1添加 if( flag ) {num[c[u]] ++;if( num[c[u]] > cnt )cnt = num[c[u]], ans = c[u];else if( num[c[u]] == cnt ) ans += c[u];}	elsenum[c[u]] --;for( int i = 0;i < G[u].size();i ++ )if( G[u][i] != fa ) modify( G[u][i], u, flag );
}void dfs2( int u, int fa ) {for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa || v == son[u] ) continue;dfs2( v, u );modify( v, u, 0 );//计算完轻儿子的答案后 要把儿子的痕迹擦干净 cnt = ans = 0;}if( son[u] ) dfs2( son[u], u );//重儿子的贡献仍然保留 for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa || v == son[u] ) continue;else modify( v, u, 1 );}num[c[u]] ++;if( num[c[u]] > cnt ) ans = c[u], cnt = num[c[u]];else if( num[c[u]] == cnt ) ans += c[u];result[u] = ans;
}signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ )scanf( "%lld", &c[i] );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs1( 1, 0 );dfs2( 1, 0 );for( int i = 1;i <= n;i ++ )printf( "%lld ", result[i] );return 0;
}

CF208E Blood Cousins

solution

可以考虑加一个假根000,将森林变成一棵树 这个操作很常见
然后考虑转换一下题意=>uuukkk级祖先的儿子有多少个,变成求同深度的uuu的兄弟伙个数

code

#include <cstdio>
#include <vector>
using namespace std;
#define ll long long
#define N 100005
vector< int > G[N];
vector< pair < int, int > > query[N];
int n, m;
bool vis[N];
int son[N], dep[N], Size[N];
ll cnt[N], ans[N];
int f[N][20];void dfs1( int u, int fa ) {Size[u] = 1;dep[u] = dep[fa] + 1;f[u][0] = fa;for( int i = 1;i < 20;i ++ )f[u][i] = f[f[u][i - 1]][i - 1];for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;dfs1( v, u ), Size[u] += Size[v];if( Size[v] > Size[son[u]] || ! son[u] )son[u] = v;}
}int kthF( int u, int k ) {for( int i = 0;i < 20;i ++ )if( ( 1 << i ) & k ) u = f[u][i];return u;
}void modify( int u, int fa, int k ) {cnt[dep[u]] += k;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa || vis[v] ) continue;modify( v, u, k );}
}void dfs2( int u, int fa, int type ) {for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa || v == son[u] ) continue;dfs2( v, u, 0 );}if( son[u] ) dfs2( son[u], u, 1 ), vis[son[u]] = 1;modify( u, fa, 1 );for( int i = 0;i < query[u].size();i ++ )//-1是减去自己ans[query[u][i].second] = cnt[query[u][i].first + dep[u]] - 1;if( son[u] ) vis[son[u]] = 0;if( ! type ) modify( u, fa, -1 );
}signed main() {scanf( "%d", &n );for( int i = 1, x;i <= n;i ++ ) {scanf( "%d", &x );G[i].push_back( x );G[x].push_back( i );}dfs1( 0, 0 );scanf( "%d", &m );for( int i = 1, u, k;i <= m;i ++ ) {scanf( "%d %d", &u, &k );int Fa = kthF( u, k );//找到自己的k级父亲 用lca跑if( ! Fa ) continue;query[Fa].push_back( make_pair( k, i ) );}dfs2( 0, 0, 0 );for( int i = 1;i <= m;i ++ ) printf( "%lld ", ans[i] );return 0;
}

CF570D Tree Requests

solution

题目已经有所放水,因为可以把字符打乱排序
所以肯定是≤1\le11个字符出现了奇数次,其它字符必须出现偶数次
对出现了奇数次的字符个数进行维护即可

code

#include <cstdio>
#include <vector>
using namespace std;
#define N 500005
vector < int > G[N];
vector < pair < int, int > > query[N];
int n, m;
int t[N], son[N], dep[N], num[N], tot[N], ans[N], Size[N];
bool vis[N];
int cnt[N][30];void dfs1( int u, int fa ) {Size[u] = 1, dep[u] = dep[fa] + 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;dfs1( v, u );Size[u] += Size[v];if( ! son[u] || Size[v] > Size[son[u]] )son[u] = v;}
}void modify( int u, int fa, int k ) {cnt[dep[u]][t[u]] += k;num[dep[u]] += k;if( cnt[dep[u]][t[u]] & 1 ) tot[dep[u]] ++;else tot[dep[u]] --;for( int i = 0;i < G[u].size();i ++ )if( G[u][i] != fa && ! vis[G[u][i]] )modify( G[u][i], u, k );
}void dfs2( int u, int fa, bool flag ) {for( int i = 0;i < G[u].size();i ++ )if( G[u][i] != fa && G[u][i] != son[u] )dfs2( G[u][i], u, 0 );if( son[u] ) dfs2( son[u], u, 1 ), vis[son[u]] = 1;modify( u, fa, 1 );for( int i = 0;i < query[u].size();i ++ )ans[query[u][i].second] = ( num[query[u][i].first] == 0 || tot[query[u][i].first] <= 1 );if( son[u] ) vis[son[u]] = 0;if( ! flag ) modify( u, fa, -1 );
}char s[N];int main() {scanf( "%d %d", &n, &m );for( int i = 2, x;i <= n;i ++ ) {scanf( "%d", &x );G[x].push_back( i );G[i].push_back( x );}scanf( "%s", s );for( int i = 0;i < n;i ++ )t[i + 1] = s[i] - 'a';dfs1( 1, 0 );for( int i = 1, x, y;i <= m;i ++ ) {scanf( "%d %d", &x, &y );query[x].push_back( make_pair( y, i ) );}dfs2( 1, 0, 1 );for( int i = 1;i <= m;i ++ )if( ans[i] ) printf( "Yes\n" );else printf( "No\n" );return 0;
}

CF1009F Dominant Indices

solution

与例题的维护操作差不多,这里用的是depdepdep深度差求kkk

code

#include <cstdio>
#include <vector>
using namespace std;
#define N 1000005
vector < int > G[N];
int n, Max;
int son[N], dep[N], Size[N];
int ans[N], cnt[N];
bool vis[N];void dfs1( int u, int fa ) {Size[u] = 1, dep[u] = dep[fa] + 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;dfs1( v, u );Size[u] += Size[v];if( ! son[u] || Size[v] > Size[son[u]] )son[u] = v;}
}void modify( int u, int fa, int k ) {cnt[dep[u]] += k;if( cnt[dep[u]] > cnt[Max] || ( cnt[dep[u]] == cnt[Max] && dep[u] < Max ) )Max = dep[u];for( int i = 0;i < G[u].size();i ++ )if( G[u][i] != fa && ! vis[G[u][i]] )modify( G[u][i], u, k );
}void dfs2( int u, int fa, bool flag ) {for( int i = 0;i < G[u].size();i ++ )if( G[u][i] != fa && G[u][i] != son[u] )dfs2( G[u][i], u, 0 );if( son[u] ) dfs2( son[u], u, 1 ), vis[son[u]] = 1;modify( u, fa, 1 );ans[u] = Max - dep[u];if( son[u] ) vis[son[u]] = 0;if( ! flag ) modify( u, fa, -1 );
}int main() {scanf( "%d", &n );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs1( 1, 0 );dfs2( 1, 0, 1 );for( int i = 1;i <= n;i ++ )printf( "%d\n", ans[i] );return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

领域驱动设计,让程序员心中有码(七)

领域驱动设计- 让程序员心中有码&#xff08;七&#xff09;-设计原则和设计模式&#xff0c;互联网开发者们共同的追求前言多年来&#xff0c;笔者一直从事传统软件企业的软件开发和项目管理工作。笔者发现在众多的传统软件企业中&#xff0c;评判优秀开发者的标准往往是技能的…

cf1504. Travelling Salesman Problem

cf1504. Travelling Salesman Problem 题意&#xff1a; n个城市&#xff0c;编号1~n&#xff0c;每个城市有美丽值a[i]&#xff0c;现在要从城市1出发&#xff0c;其他所有城市走一遍&#xff0c;最后回到城市1&#xff0c;城市i到j的花费为max(ci,aj-ai)&#xff0c;ci为第…

[NOIP-S 2020]游记(附考前注意事项)

呜呼起飞T1&#xff1a;排水系统T2&#xff1a;字符串匹配T3&#xff1a;移球游戏T4&#xff1a;微信步数总述考前注意事项T1&#xff1a;排水系统 嗯—— 怎么说呢&#xff1f;&#xff1f; 比赛开始后迅速通读三遍题 顶着第一题肯定是打卡题的心态 哪怕是恶心模拟也得上&…

程序猿修仙之路--数据结构之你是否真的懂数组?

数据结构但凡IT江湖侠士&#xff0c;算法与数据结构为必修之课。早有前辈已经明确指出&#xff1a;程序算法数据结构 。要想在之后的江湖历练中通关&#xff0c;数据结构必不可少。数据结构与算法相辅相成&#xff0c;亦是阴阳互补之法。开篇说道数组&#xff0c;几乎每个IT江…

Rolling The Polygon Gym - 102222B

Rolling The Polygon Gym - 102222B 题意&#xff1a; 给你一个多边形&#xff0c;给你内部一个点Q&#xff0c;多边形在平面上滚动一周&#xff08;当有一个边第二次触地滚动停止&#xff09;&#xff0c;问Q的轨迹长度 题解&#xff1a; 计算几何题目 自己一直不是很擅长…

Asp.Net Core 轻松学-经常使用异步的你,可能需要看看这个文章

前言事情的起因是由于一段简单的数据库连接代码引起&#xff0c;这段代码从语法上看&#xff0c;是没有任何问题&#xff1b;但是就是莫名其妙的报错了&#xff0c;这段代码极其简单&#xff0c;就是打开数据库连接&#xff0c;读取一条记录&#xff0c;然后立即更新到数据库中…

try.dot.net 的正确使用姿势

来源&#xff1a;https://www.cnblogs.com/7tiny/p/10277600.html【简介】微软官方前不久发布了 try.dot.net 这个有趣的网址&#xff0c;开始只是图个新鲜看了一下&#xff0c;后面通过自身实践过后&#xff0c;发现这着实算是个“有趣”的站点&#xff01;首先我们大概地列举…

A - TOYS POJ - 2318

A - TOYS POJ - 2318 题意&#xff1a; 一个盒子中有n个隔板&#xff0c;分出n1个空间&#xff08;从左往右空间的编号分别是0…n&#xff09;&#xff0c;&#xff08;隔板之间不会相交&#xff0c;且按照从左往右的顺序给出&#xff09;&#xff0c;现在给你m个坐标的物品&…

[BJOI2017]魔法咒语(AC自动机+DP+矩阵快速幂)

文章目录titlesolutioncodetitle solution 针对数据编程才是坠吊的&#xff01;&#xff01;&#xff01; 观察数据&#xff0c;发现分隔数据的LLL跨度过大&#xff0c;没有衔接——推测很有可能是分数据做法 ①&#xff1a;考虑L≤100L\le100L≤100的情况 可以暴力DPDPDP转移…

[国家集训队]middle(二分+主席树[中位数思维题])

文章目录点击查看solutioncode点击查看 solution 简单口胡一下就跑 考虑二分答案ansansans 区间[x1,x2],x1∈[a,b]&#xff0c;x2∈[c,d][x1,x2],x1∈[a,b]&#xff0c;x2∈[c,d][x1,x2],x1∈[a,b]&#xff0c;x2∈[c,d] 大于等于ansansans的设为111&#xff0c;小于ansans…

使用Roslyn脚本化C#代码,C#动态脚本实现方案

来源&#xff1a;https://www.cnblogs.com/7tiny/p/10279349.html【前言】Roslyn 是微软公司开源的 .NET 编译器。编译器支持 C# 和 Visual Basic 代码编译&#xff0c;并提供丰富的代码分析 API。Roslyn不仅仅可以直接编译输出&#xff0c;难能可贵的就是上述描述中的开放了编…

[构造训练]CF1227G Not Same,CF1375H Set Merging,CF1364E X-OR

文章目录T1&#xff1a;CF1227G Not SamesolutioncodeT2&#xff1a;CF1364E X-ORsolutioncodeT3&#xff1a;CF1375H Set Mergingsolutioncode~~脑子是个好东西&#xff0c;希望人人都有构造真的不是个东西&#xff0c;看了一天视频&#xff0c;没有一道题会做~~ T1&#xff…

asp.net core 环境(Development、Staging 、Production)

一.在asp.net core中使用多个环境ASP.NET Core 配置是基于运行时环境, 使用环境变量。ASP.NET Core 在应用启动时读取环境变量ASPNETCORE_ENVIRONMENT&#xff0c;并将该值存储在 IHostingEnvironment.EnvironmentName 中。ASPNETCORE_ENVIRONMENT 可设置为任意值&#xff0c;但…

ASP.NET Core 2.1 : 图解路由(2.1 or earler)

本文通过一张图来看一下路由的配置以及请求处理的机制。 一、概述路由主要有两个主要功能&#xff1a;将请求的URL与已定义的路由进行匹配&#xff0c;找到该URL对应的处理程序并传入该请求进行处理。根据已定义的路由生成URL这两个功能看起来这两个是相反的。A.路由的配置路由…

[数据结构专训][GXOI/GZOI2019]旧词,[hdu5118]GRE Words Once More!,[hdu6333]Problem B. Harvest of Apples

文章目录T1&#xff1a;[GXOI/GZOI2019]旧词solutioncodeT2&#xff1a;GRE Words Once More!solutioncodeT3&#xff1a;Problem B. Harvest of ApplessolutioncodeT1&#xff1a;[GXOI/GZOI2019]旧词 点击查看 solution 考虑k1k1k1的情况 由于dep[lca(x,y)]∣{z,zdep[lca(…

浅谈c#垃圾回收机制(GC)

写了一个window服务&#xff0c;循环更新sqlite记录&#xff0c;内存一点点稳步增长。三天后&#xff0c;内存溢出。于是&#xff0c;我从自己的代码入手&#xff0c;查找到底哪儿占用内存释放不掉&#xff0c;最终明确是调用servicestack.ormlite更新sqlite数据库造成的。至于…

洛谷P2497:基站建设(splay、斜率优化)

所谓splay斜率优化dp&#xff0c;就是利用splay和斜率对dp进行优化 &#xff08;逃&#xff09; 解析 在斜优的时候&#xff0c;有时我们会发现我们插入的点的横坐标并不单调 这个时候我们就无法利用单调队列维护凸包了 这时&#xff0c;我们就要请出今天的主角&#xff1a;s…

MediatR 知多少

引言首先不用查字典了&#xff0c;词典查无此词。猜测是作者笔误将Mediator写成MediatR了。废话少说&#xff0c;转入正题。先来简单了解下这个开源项目MediatR&#xff08;作者Jimmy Bogard&#xff0c;也是开源项目AutoMapper的创建者&#xff0c;在此表示膜拜&#xff09;&a…

网络分析(带权并查集)

网络分析 题意&#xff1a; 有n个节点&#xff0c;一开始彼此独立&#xff0c;有两个操作&#xff0c;第一个操作时是连接两个节点&#xff0c;第二个操作是对一个节点x&#xff0c;&#xff08;在进行第二个操作时&#xff0c;与该点相连的点也会x&#xff09; 问每个节点的…

良心发现,时隔一年再回首莫比乌斯反演(公式性质证明+题目练习)

文章目录莫比乌斯反演引入公式性质模板公式证明莫比乌斯函数前缀和题目练习完全平方数[HAOI2011]ProblembYY的GCD[SDOI2014]数表[国家集训队]Crash的数字表格/JZPTAB[SDOI2015]约数个数和寒假疫情期间跟着lmm学了一遍&#xff0c;完全是懵逼到底状态&#xff0c;以至于后面考到…