L3-032 关于深度优先搜索和逆序对的题应该不会很难吧这件事 有趣的数据结构题

news2024/9/21 4:38:55

传送门:PTA

题目描述:

给定一棵 n 个节点的树,其中节点 r 为根。求该树所有可能的 DFS 序中逆序对数量之和。
输入:
10 5
10 2
2 5
10 7
7 1
7 9
4 2
3 10
10 8
3 6
输出:
516

唉,由于近期事情比较多以及某些个人因素导致好久没有更新博客了,今天碰到了一道有意思的数据结构题,故决定更新一篇博客

首先看完题目会发现题意十分简单,就是求所有 d f s dfs dfs序的逆序对数总和

显然对于一个点 u u u来说,因为枚举 u u u的儿子 v i vi vi的顺序不同会导致不同的逆序对.把玩一下 d f s dfs dfs的遍历方式,我们会发现一些有意思的规律

对于树上的两个点 u , v u,v u,v来说,假设 u , v u,v u,v是祖先和儿子关系(不妨假设 u u u是祖先),那么根据我们的 d f s dfs dfs的遍历顺序,我们会发现无论怎么遍历 u u u d f s dfs dfs序的位置肯定是在 v v v的前面的.那么对于所有的点对 u , v u,v u,v来说,都可以对答案进行一个贡献.那么此时的贡献总数显然就是一棵树中这样的 u , v u,v u,v的个数 ∗ * d f s dfs dfs序的个数.对于 d f s dfs dfs序的个数的求法,等会再详细介绍.

再来讲一下如何求出这样的点对的个数.我们可以使用树状数组进行维护.具体操作方法可以见这道题.在那道题中我有详细解释,此处就不在赘述了.


对于树上的所有点对<u,v>来说,显然除了祖先儿子的关系还有一种就是不是祖先儿子的关系.对于这样的点对<u,v>来说,因为 u u u v v v肯定是不同的,又因为不是祖先儿子的关系,所以在 d f s dfs dfs序中肯定存在这样的情况: u u u v v v的前面或者 v v v u u u的前面,那么对于上述两种情况来说,此时两种情况肯定是有且只有一种情况是可以提供贡献的.也就是对于所有的 d f s dfs dfs序来说,有一半 d f s dfs dfs序的点对<u,v>是可以进行贡献的.那么此时我们的总贡献就是所有的 d f s dfs dfs序的个数的一半乘上所有的这样的点对<u,v>的个数

现在再来讲一下这样的<u,v>的个数应该怎么求.

int kkk=0;
for(int i=0;i<edge[u].size();i++) {
		int v=edge[u][i];
		if(v==per_u) continue;
		dfs(v,u);
		Size[u]+=Size[v];
		sum2=(sum2+Size[v]*kkk%mod)%mod;
		kkk=(kkk+Size[v])%mod;
	}

在这里插入图片描述
假设我们有这样一棵树,枚举到了u,此时我们统计一下u这棵子树的所有答案.
我们会发现有两种情况:
1.一种情况就是 v 1 , v 2 , v 3 v1,v2,v3 v1,v2,v3的自身子树的点对个数,这种情况我们可以使用类似于分治的思想在dfs中顺便解决,因为求出自身的点对个数的方法就是求出u这棵子树的方法
2. v 1 , v 2 , v 3 v1,v2,v3 v1,v2,v3跨子树构成的点对.我们可以这样进行统计,当枚举到 v i vi vi时,我们记 v i vi vi的贡献就是 S i z e [ v i ] ∗ ∑ k = 1 i − 1 S i z e [ k ] Size[vi]*\sum_{k=1}^{i-1}Size[k] Size[vi]k=1i1Size[k].这样我们可以不重不漏的计算出所有的点对个数


现在再来讲一下如何求出 d f s dfs dfs序的个数.对于当前的u节点来说,存在儿子 v i vi vi,那么此时的 d f s dfs dfs序来说,我们会发现显然所有的父亲和儿子节点在 d f s dfs dfs序中显然是连在一起的(可能有点抽象,仔细理解一下).那么我们此时有两种改变 d f s dfs dfs的方法,一种就是调整 v i vi vi的儿子节点的遍历顺序,另一种就是调整 v i vi vi的遍历顺序.总贡献显然就是两者相乘.我们会发现调整 v i vi vi的遍历顺序的方法数是 S i z e [ u ] ! Size[u]! Size[u]!.我们此时又可以使用分治的思想不断递归的去解决这道题.我们会发现最终的总贡献就是所有的 S i z e [ u ] Size[u] Size[u]相乘,也就是所有的节点的子节点个数相乘.简单来说就是只要一个节点枚举子节点的顺序不同,最终产生的 DFS 序就不同。因此 DFS 序的总数就是所有节点子节点数量阶乘相乘。

因为取模的原因,对于除2我们需要使用逆元进行解决

下面是具体的代码部分;

#include <bits/stdc++.h>
using namespace std;
#define maxn 300010
#define int long long
const int mod=1e9+7;
int n,r;
inline int lowbit(int x) {
	return x&(~x+1);
}
int tree[maxn];
void Add(int pos,int val) {
	while(pos<=n) {
		tree[pos]+=val;
		pos+=lowbit(pos);
	}
}
int query(int pos) {
	int ans=0;
	while(pos) {
		ans+=tree[pos];
		pos-=lowbit(pos);
	}
	return ans;
}
int fac[maxn];
void init() {
	fac[0]=1;
	for(int i=1;i<=n;i++) {
		fac[i]=fac[i-1]*i%mod;
	}
}
int qpow(int a,int b) {
	int ans=1;
	while(b) {
		if(b&1) ans=(ans*a)%mod;
		b>>=1;
		a=(a*a)%mod; 
	}
	return ans;
} 
vector<int>edge[maxn];
int sum1=0;int sum2=0;int Size[maxn];int Z=1;
void dfs(int u,int per_u) {
	Size[u]=1;
	sum1=(sum1+query(n)-query(u))%mod;
	Add(u,1);
	int kkk=0;int kk=0;
	for(int i=0;i<edge[u].size();i++) {
		int v=edge[u][i];
		if(v==per_u) continue;
		dfs(v,u);kk++;
		Size[u]+=Size[v];
		sum2=(sum2+Size[v]*kkk%mod)%mod;
		kkk=(kkk+Size[v])%mod;
	}
	Add(u,-1);
	Z=(Z*fac[kk])%mod;
}
signed main() {
 	cin.sync_with_stdio(false);
	cin>>n>>r;
	init();
 	for(int i=1;i<=n-1;i++) {
 		int u,v;cin>>u>>v;
 		edge[u].push_back(v);
 		edge[v].push_back(u);
	}
	dfs(r,0);
	sum1=(sum1*Z)%mod;
	sum2=(sum2*Z)%mod*qpow(2,mod-2)%mod;
	cout<<(sum1+sum2)%mod<<endl;
	return 0;
}

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

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

相关文章

机器视觉检测技术在工业零部件的应用

众所周知&#xff0c;在工业生产中&#xff0c;传统的检测技术需要大量的检测工作者&#xff0c;不仅影响生产效率&#xff0c;而且带来不可靠的因素。 视觉检测技术克服了传统检测技术的缺点&#xff0c;确保了检测的安全性。 可靠性和自动化程度高&#xff0c;已成为当前检测…

Scrapy配置使用

前人之述备矣 教程&#xff1a;Python虚拟环境ScrapyPyCharm 使用实例 - 知乎 注意&#xff1a;是cmd不是powershell,两者还是有区别的。 因为是本地的虚拟环境&#xff0c;用cmd激活环境并且安装相关的scrapy包&#xff0c;如果用powershell&#xff0c;在pycharm中显示不了…

【MySQL】如何使用MySQL锁(全局锁、表级锁、行级锁)?

文章目录 概述一、全局锁介绍语法特点 二、表级锁介绍表锁元数据锁意向锁 三、行级锁介绍行锁间隙锁&临键锁 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xf…

神经网络之反向传播算法(自适应矩估计算法Adam)

文章目录 自适应矩估计算法&#xff08;Adam&#xff09;1、算法原理2、算法实现2.1 训练过程2.2 测试过程及结果 3、参考源码及数据集 自适应矩估计算法&#xff08;Adam&#xff09; 自适应矩估计算法从其本质上看可以视作是带有动量项的均方根反向传播算法&#xff0c;一方…

jmeter -- WebService接口压测

WebService简介 webService 一种使用http传输SOAP协议数据的远程调用技术。 SOAP协议 soap请求是HTTP POST的一个专用版本&#xff0c;遵循一种特殊的xml消息格格式。Content-type需设置为: text/xml 与HTTP比较 接口中实现的方法和要求参数一目了然不用担心大小写问题不用担心…

matlab中计算标准差std函数

标准差 标准差&#xff08;Standard Deviation&#xff09;是离均差平方的算术平均数&#xff08;即&#xff1a;方差&#xff09;的算术平方根。 标准差是方差的算术平方根。标准差能反映一个数据集的离散程度。平均数相同的两组数据&#xff0c;标准差未必相同。 计算公式&…

HCIP之路VLAN

VLAN---虚拟局域网 垃圾流量问题 网络安全问题 VLAN特点 一个vlan就是一个广播域&#xff0c;不同vlan内部的数据无法进行跨广播域通讯 vlan的划分不受地域限制 vlan的实现 主机的网卡一般只能发送和接收无标记帧&#xff08;Untagged Frame&#xff09;。Tagged Frame --- 标…

【Linux】生产者消费者模型——阻塞队列BlockQueue

文章目录 一、生产者消费者模型生产消费理解生产消费关系 二、基于blockqueue的生产和消费模型单生产单消费计算随机数计算器任务Task存储任务 多生产多消费 三、总结 一、生产者消费者模型 生产消费理解 引入&#xff1a;举个例子&#xff0c;比如我们学生想买东西&#xff…

Tomcat服务器

1.服务器概念&#xff1a; 服务器是一个容器&#xff0c;可以将任何资源放到服务器中&#xff0c;服务器启动后 外部用户可以通过 ip地址:端口/资源路径 来访问服务器容器内对应的资源 你可以将服务器理解为一个共享文件夹&#xff0c;只要服务器启动了&#xff0c;大家都可…

人社LEAF平台架构及其主要技术架构特点

人社LEAF平台架构及其主要技术架构特点https://wheart.cn/so/home?mindex&id31525d77-de79-11ed-96fa-52540016e6ac 在前面的系列文章中介绍了社会保险管理信息系统核心平台三版&#xff08;以下简称核三&#xff09;的技术亮点&#xff0c;这些技术亮点主要是由核三的技…

WebGIS:前端:给出地理范围计算出地图瓦片的行列号

目录 前端代码实现 根据xml配置文件计算出行列号 1、xml配置文件信息样例 2、代码实现 运用到的知识 该文档是根据本人做的项目进行的总结&#xff0c;可能存在知识不准确&#xff0c;仅做参考&#xff1b; 前端代码实现 根据提供一个瓦片服务地址&#xff0c;解析服务的…

【Linux】Linux入门手册

入门Linux Linux的目录结构Linux的远程操作Xshell 软件Xftp 软件 Linux 基础命令vi 和 vimLinux中的用户管理Linux中的组管理Linux中的权限管理文件或者目录中的三种权限修改文件或者目录的权限使用数字的方式修改文件或者目录的权限 Linux中的帮助命令Linux目录相关命令Linux查…

关于数制及其转换

关于数制及其转换 从1除以10谈起 十进制计算 1 10 0.1 商是有限小数 用二进制计算 是无限循环小数&#xff1a; 1 1010 0.00011001100110011…… 1/10 是无法用二进制小数精确表示的。十进制小数转换成二进制有可能无限循环。 十进制数0.1转换成二进制为0.00011000…

C++程序设计—类与对象

目录 1、类和对象的概念 2、面向对象程序设计的特点 3、类和对象的区别 4、成员运行算符 &#xff08;1&#xff09;&#xff08;.&#xff09;点运算符 &#xff08;2&#xff09;&#xff08;->&#xff09;箭头运算符 5、类的声明形式 &#xff08;1&#xff09;…

DataBinding 大坑总结(网上我暂时搜不到解决方法)

在使用多Module中使用DataBinding会引发一些奇怪的问题&#xff0c;最近好好的腾出时间来折腾这些奇怪的问题&#xff1a; 1&#xff1a;如果当Module启动DataBinding重启AS启动报错的话&#xff0c;就启用允许多行代码 android { defaultConfig {multiDexEnabled true} } de…

设计模式:UML中的类图(6种关系)

一.UML图介绍 统一建模语言是用来设计软件的可视化建模语言。它的特点是简单、统一、图形化、能表达软件设计中的动态与静态信息。 UML 从目标系统的不同角度出发&#xff0c;定义了用例图、类图、对象图、状态图、活动图、时序图、协作图、构件图、部署图等 9 种图。 二.类图…

apkanalyzer-classpath.jar 中没有.class 文件

apkanalyzer-classpath.jar 中没有.class 文件&#xff0c;apkanalyzer-classpath.jar 包目录下&#xff0c;只有 MANIFEST.MF 文件&#xff0c;如下截图&#xff1a; 而 apkanalyzer.jar 下&#xff0c;有很多 class 文件&#xff0c;其中&#xff0c;BinaryXmlParser.class 就…

P80-MySQL

//启动mysql&#xff0c;我的名字是mysql80 net start mysql80//我的端口号为3307 mysql -hlocalhost -P3307 -uroot -p一、课程介绍 什么是数据库? 数据库&#xff1a;DataBase&#xff08;DB&#xff09;&#xff0c;是存储和管理数据的仓库。

ChatGPT账号被封怎么办?进来看看解决办法

部分内容整理自网络&#xff0c;侵删 最近有很多同学说自己的chatgpt账号被封了。仔细研究了一下大部分被封账号&#xff0c;发现主要有这些个原因&#xff1a; 1&#xff0c;被封的账号可能是用程序批量注册的&#xff0c;也就是一台机器用一个IP在短时间内注册了大量的账号 …

JSON Web Tokens (JWT) — the only explanation you will ever need

本文摘抄自 Ariel Weinberger 博客 JSON Web Tokens (JWT) — the only explanation you will ever need | by Ariel Weinberger | Medium JSON Web Tokens (JWT) — the only explanation you will ever need JSON Web Tokens are changing the world for the better. Acting …