首页 > 其他分享 >Living-Dream 系列笔记 第62期

Living-Dream 系列笔记 第62期

时间:2024-07-23 15:59:10浏览次数:15  
标签:Living cur dis1 int sum dfs fa 62 Dream

树的直径:

  • 定义:树上两个距离最远的点形成的简单路径(不重复走一条边 / 点)

  • 性质:

    • 不唯一。

    • 树的直径的端点一定是度数为 \(1\) 的点。

      证明:显然。

    • 树的直径若有多条,则必交汇于一点,即中心。

      证明:首先每条直径只能交于端点(因为是一棵树,一个节点不能有两个父节点),然后此交点必定为最长链最短的节点即中心(因为它度数为 \(1\),没有父节点,并且它的子节点的最长链是子节点到它的距离加上直径,一定不比直径小)。

    • 树上任意点 \(u\) 距离其最远的点一定为树的直径的端点。

      证明:根据直径最长的定义易证。

  • 求法:

    • 2 遍 dfs

      • 原理:性质三。

        • 从任意点 \(u\) 出发 dfs 找到距 \(u\) 最远的点 \(x\),\(x\) 为端点;

        • 从 \(x\) 出发找到距 \(x\) 最远的点 \(y\),\(y\) 为端点;

        • \(x \to y\) 的简单路径即为树的一条直径。

        \(O(n)\),仅用于边权非负的树。

    • 树形 dp

      • 原理:性质二,枚举中心,将最长链与次长链拼接。

        • 定义 dis1[i] 表示以点 i 为根的最长链,dis2[i] 为次长链;

        • 转移:

        dfs(nxt,cur); //先递归再转移
        if(dis1[nxt]+w>dis1[cur])
        	dis2[cur]=dis1[cur], 
        	dis1[cur]=dis1[nxt]+w;
        else if(dis1[nxt]+w>dis2[cur]) 
        	dis2[cur]=dis1[nxt]+w;
        
        • 枚举点 i,取 max(dis1[i]+dis2[i]) 即为直径长度。
          \(O(n)\),可以有负边权。

https://www.luogu.com.cn/problem/SP1437

板子。

法一
#include<bits/stdc++.h>
using namespace std;

const int N=5e5+5;
int n,x,dis;
struct edge{ int v,w; };
vector<edge> G[N];
bool vis[N];

void dfs(int cur,int sum){
	vis[cur]=1;
	if(sum>=dis)
		dis=sum,x=cur;
	for(auto i:G[cur])
		if(!vis[i.v])
			dfs(i.v,sum+i.w);
}

int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v,w; cin>>u>>v>>w;
		G[u].push_back({v,w}),
		G[v].push_back({u,w});
	}
	dfs(1,0);
    memset(vis,0,sizeof vis);
    dfs(x,0);
	cout<<dis;
	return 0;
}
-------
法二
#include<bits/stdc++.h>
using namespace std;

const int N=5e5+5;
int n,x,ans;
struct edge{
	int v,w;
};
vector<edge> G[N];
int dis1[N],dis2[N];

void dfs(int cur,int fa){
	for(auto i:G[cur]){
		if(i.v==fa) continue;
        dfs(i.v,cur);
		if(dis1[i.v]+i.w>dis1[cur])
			dis2[cur]=dis1[cur],
			dis1[cur]=dis1[i.v]+i.w;
		else if(dis1[i.v]+i.w>dis2[cur])
			dis2[cur]=dis1[i.v]+i.w;
	}
	ans=max(ans,dis1[cur]+dis2[cur]);
}

int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v,w; cin>>u>>v>>w;
		G[u].push_back({v,w}),
		G[v].push_back({u,w});
	}
	dfs(1,-1);
	cout<<ans;
	return 0;
}

https://www.luogu.com.cn/problem/CF455C & https://www.luogu.com.cn/problem/P2195

我们发现两个树连边连中心得到的新树直径最短(由中心的定义易证)。

然后我们发现中心的一个性质:当中心为根时,其到直径两端点的距离分别为最长和非严格次长链(由直径的定义易证),又因为中心的最长链最短,于是这相当于中心将直径劈成了两半,每一半都是 \(\lceil \frac{直径长度}{2} \rceil\)。

因此我们用并查集虚拟连边维护联通性(假定以中心为根),并维护每个节点所在树的直径这一信息,每次连边的新直径即为 \(\max(z_x,z_y,\lceil \frac{z_x}{2} \rceil + \lceil \frac{z_y}{2} \rceil + 1)\)(\(z_x,z_y\) 表示要连边的两点 \(x,y\) 所在树的直径)。

code
#include<bits/stdc++.h>
using namespace std;

const int N=3e5+5;
int n,m,q;
vector<int> G[N];
int x,dis;
int fa[N],z[N];

void dfs(int cur,int fa,int sum){
	if(sum>=dis)
		dis=sum,x=cur;
	for(int i:G[cur])
		if(i!=fa)
			dfs(i,cur,sum+1);
}
int fnd(int x){
	return (x==fa[x]?x:fa[x]=fnd(fa[x]));
}
void uni(int x,int y){
	x=fnd(x),y=fnd(y);
	if(x!=y)
		z[y]=max((z[x]+1)/2+(z[y]+1)/2+1,max(z[x],z[y])),
		fa[x]=y;
}

int main(){
	ios::sync_with_stdio(0);
	cin>>n>>m>>q;
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1,u,v;i<=m;i++)
		cin>>u>>v,
		G[u].push_back(v),
		G[v].push_back(u),
		uni(u,v);
	for(int i=1;i<=n;i++){
		if(fa[i]==i){
			x=dis=0;
			dfs(i,0,0),dfs(x,0,0);
			z[i]=dis;		
		}
	}
	while(q--){
		int op,x,y; cin>>op>>x;
		if(op==1) cout<<z[fnd(x)]<<'\n';
		else cin>>y,uni(x,y);
	}
	return 0;
}

https://www.luogu.com.cn/problem/CF1404B

Case 1:一步到位。\(dis_{a,b} \le da\)。

Case 2:Alice 必然会将 Bob 赶进某棵子树,则 Bob 就会在某一时刻折返,此时 Alice 仅需走 Bob 一半及以上距离即可。\(2da \ge db\)。

Case 3:Alice 在中心时,仅需覆盖最长链即可覆盖整棵树。\(\lceil \frac{树的直径}{2} \rceil \le da\)。

code
#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5;
int t,n,a,b,da,db;
int x,dis,disab;
vector<int> G[N];

void dfs(int cur,int fa,int sum){
	if(sum>=dis)
		dis=sum,x=cur;
	for(int i:G[cur])
		if(i!=fa)
			dfs(i,cur,sum+1);
}
void dfsab(int cur,int fa,int sum){
	if(cur==b){
		disab=sum; return;
	}
	for(int i:G[cur])
		if(i!=fa)
			dfsab(i,cur,sum+1);
}
void init(){
    x=dis=disab=0;
    for(int i=1;i<=n;i++) G[i].clear();
}
void sol(){
    init();
	cin>>n>>a>>b>>da>>db;
	for(int i=1,u,v;i<n;i++)
		cin>>u>>v,
		G[u].push_back(v),
		G[v].push_back(u);
	dfs(1,0,0),dfs(x,0,0),dfsab(a,0,0);
	//cout<<dis<<' '<<disab<<'\n';
	if(da>=disab) cout<<"Alice\n";
	else if(da>=(dis+1)/2) cout<<"Alice\n";
	else if(2*da>=db) cout<<"Alice\n";
	else cout<<"Bob\n";
}

int main(){
	cin>>t;
	while(t--) sol();
	return 0;
}

标签:Living,cur,dis1,int,sum,dfs,fa,62,Dream
From: https://www.cnblogs.com/XOF-0-0/p/18318627

相关文章

  • MDK Keil5创建stm32工程出现 …\OBJ\Template.axf: Error: L6200E: Symbol HAL_MspD
    MDKKeil5创建stm32工程出现…\OBJ\Template.axf:Error:L6200E:SymbolHAL_MspDeInitmultiplydefined(bystm32f7xx_hal_msp_template.oandstm32f7xx_hal_msp.o).错误的解决方法错误提示如图: 解决方法如下:1.找到左边目录,右键选择manageprojectitems,找到对应文件,删除......
  • SSM小说阅读网站-计算机毕业设计源码11362
    摘 要本文介绍了一个基于SSM框架和MySQL数据库的小说阅读网站的设计与实现。该网站旨在为用户提供一个方便、舒适的在线小说阅读平台。该小说阅读网站具有以下主要功能:用户注册与登录、小说分类浏览、小说搜索、阅读历史记录、小说畅听等。通过该网站,用户可以根据自己的兴......
  • 代码随想录算法训练营第36天 | 动态规划基础2:62.不同路径、63.不同路径 II
    62.不同路径https://leetcode.cn/problems/unique-paths/submissions/548656029/代码随想录https://programmercarl.com/0062.不同路径.html63.不同路径IIhttps://leetcode.cn/problems/unique-paths-ii/description/代码随想录https://programmercarl.com/0063.不同路径......
  • 【精品资料】大数据可视化平台数据治理方案(626页WORD)
    引言:大数据可视化平台的数据治理方案是一个综合性的策略,旨在确保大数据的质量、安全性、可访问性和合规性,从而支持高效的数据分析和可视化过程。方案介绍:大数据可视化平台的数据治理方案是一个综合性的策略,旨在确保大数据的质量、安全性、可访问性和合规性,从而支持高效的数......
  • 洛谷 P1162 填涂颜色题解
    题目链接填涂颜色题目描述由数字\(0\)组成的方阵中,有一任意形状的由数字\(1\)构成的闭合圈。现要求把闭合圈内的所有空间都填写成\(2\)。例如:\(6\times6\)的方阵(\(n=6\)),涂色前和涂色后的方阵如下:如果从某个\(0\)出发,只向上下左右\(4\)个方向移动且仅经过其他\(0\)......
  • RK3562 NPU开发环境搭建
    如何在Ubuntu系统(PC)上搭建RK3562 Buildroot Linux的NPU开发环境?即电脑端运行Ubuntu系统,而RK3562板卡运行Buildroot Linux系统的情况下,搭建RK3562 NPU开发环境。下面是相应的步骤(对应的命令):1、下载RKNN相关仓库在Ubuntu电脑端执行如下命令:mkdir-p~/bigger_disk/rknpu......
  • 162. 寻找峰值
    题目链接:法一、暴力\(O(n)\)classSolution{public:intfindPeakElement(vector<int>&nums){intn=nums.size();if(n==1)return0;if(n==2){if(nums[0]<nums[1])return1;elseif(nu......
  • 洛谷B3626(跳跃机器人)解析
     这道题的网址洛谷B3626请速览一遍原题当然,咱们来进行题面关键信息提取 1.机器人从第1个格子出发;2.设机器人目前所在格子的编号为x,则它能够跳到格子的编号可能是x,x+1或2x,也就是说,新跳到格子的编号,可能是比原来格子编号少1或多1,或是其2倍;3.不允许跳出界,举个简单的例子......
  • WebGoC题解(11) 627.传声(2019NHOI小乙)
    题目描述 小C节日旅游来到一个农场。农场主John和n个奶牛站在一条水平线上。牛的传递消息是依靠“吼”,牛的吼叫声最远可以传递的距离是50。农场主John首先通知最左边的第一条奶牛(一定会通知),然后奶牛就开始向后吼叫,后面的奶牛如果能听到(和前面吼叫的奶牛距离不超过50),就继续向......
  • ABC362
    Alink判断即可。。。点击查看代码#include<bits/stdc++.h>usingnamespacestd;intr,g,b;stringc;signedmain(){ cin>>r>>g>>b>>c; if(c=="Red")cout<<min(g,b); elseif(c=="Blue")cout&l......