首页 > 其他分享 >[学习笔记] LCA - 图论

[学习笔记] LCA - 图论

时间:2024-04-11 22:36:54浏览次数:26  
标签:wg 图论 int ans deep fa 笔记 LCA dt

[NOIP2013 提高组] 货车运输

最大生成树+LCA+倍增

好家伙,这道题我写了一个晚上,调了两个晚上,对于这道题我颇有感触。但这道题确实好,实实在在的蓝题,让我发现了许多关于LCA的问题。

首先,这个题给的是一个无向图,并不是个树,为了减少运算量,我们可以把它变成一个树。运用Kruskal算法生成一颗 最大生成树(即这棵树里所有的边权都是最大的)。因为我们要求经过的路径中最短的边的最大值(有点绕),所以这颗最大生成树在保证图原本的连通性的同时,也保证了边权的最大性。

其次,求树上点到点的边权最小值,可以 \(wg[a-b]=min(wg[a-lca], wg[b-lca])\) ,也就是分别找到 \(a\) 和 \(b\) 到 \(lca\) 的最小边权即可。我们知道:求树上路径的长度可以用仅仅一个数组或者是树状数组,但是求一个树链上的最小边权可不是件容易的事。

这让我想到了与树链有关的LCA算法:倍增法。原理就是让 \(a\) 和 \(b\) 不断沿着树链向上跳,最终找到 \(lca\) 。同理,我们也可以让wg数组跟着fa数组一块儿向上跳,最后在统计答案的时候用上即可。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 1, M = 5e4 + 1;
int n, m, q, f[N], cnt, h[N], fa[21][N], wg[21][N], deep[N], scc[N], lg[N];
bitset<N> flag;
struct Edge{ int u, v, dt; }E[M];
struct edge{ int v, nt, dt; }e[N];
bool cmp(Edge a, Edge b){ return a.dt > b.dt; }
inline void add(int u, int v, int dt){ e[++cnt] = (edge){v, h[u], dt}; h[u] = cnt;}
inline int find(int k){
	if(!f[k]) return k;
	return f[k] = find(f[k]);
}
inline void kruskal(){
	sort(E+1, E+m+1, cmp);
	int eg = 0;
	for(int i=1; i<=m; ++i){
		if(eg == n-1) break;
		int fa = find(E[i].u), fb = find(E[i].v);
		if(fa == fb) continue;
		else{
			++eg;
			f[fa] = fb;
			add(E[i].u, E[i].v, E[i].dt), add(E[i].v, E[i].u, E[i].dt);
		}
	}
}
inline void dfs(int k, int f){
	scc[k] = scc[f];
	flag[k] = 1;
	deep[k] = deep[f] + 1;
	for(int i=h[k]; i; i=e[i].nt){
		int v = e[i].v;
		if(!flag[v]){
			wg[0][v] = e[i].dt;
			fa[0][v] = k;
			dfs(v, k);
//			for(int t=1; t<=lg[deep[v]]; ++t){
//				fa[t][v] = fa[t-1][fa[t-1][v]];
//				wg[t][v] = min(wg[t-1][v], wg[t-1][fa[t-1][v]]);
//			}
		}
	}
}
inline int getans(int a, int b){
	int ans = INT_MAX;
	if(deep[a] < deep[b]) swap(a, b);
//	for(int i=20; i>=0; --i){
//		if(deep[fa[i][a]] >= deep[b]){
//			ans = min(ans, wg[i][a]);
//			a = fa[i][a];
//		}
//	}
	while(deep[a] != deep[b]){
		ans = min(ans, wg[lg[deep[a]-deep[b]]][a]);
		a = fa[lg[deep[a]-deep[b]]][a];
	}
	if(a == b) return ans;
	for(int i=lg[deep[a]]; i>=0; --i)
		if(fa[i][a] != fa[i][b]){
			ans = min({ans, wg[i][a], wg[i][b]});
			a = fa[i][a], b = fa[i][b];
		}
	return min({ans, wg[0][a], wg[0][b]});
}
int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n>>m;
	lg[0] = -1;
	for(int i=1; i<=n; ++i) lg[i] = lg[i>>1] + 1;
	for(int i=1; i<=m; ++i) cin>>E[i].u>>E[i].v>>E[i].dt;
	kruskal();
	deep[0] = -1;
	for(int i=1; i<=n; ++i){
		if(!flag[i]){
			++scc[0];
			dfs(i, 0);
			fa[0][i] = i;
			wg[0][i] = INT_MAX;
		}
	}
//	for(int j=1; j<=n; ++j){
//		for(int i=1; i<=20; ++i){
//			fa[i][j] = fa[i-1][fa[i-1][j]];
//			wg[i][j] = min(wg[i-1][j], wg[i-1][fa[i-1][j]]);
//		}
//	}
	for(int i=1; i<=20; ++i){
		for(int j=1; j<=n; ++j){
			fa[i][j] = fa[i-1][fa[i-1][j]];
			wg[i][j] = min(wg[i-1][j], wg[i-1][fa[i-1][j]]);
		}
	}
	cin>>q;
	for(int i=1, a, b; i<=q; ++i){
		cin>>a>>b;
		if(scc[a] != scc[b]) cout<<"-1\n";
		else cout<<getans(a, b)<<'\n';
	}
	return 0;
}

没写完。

标签:wg,图论,int,ans,deep,fa,笔记,LCA,dt
From: https://www.cnblogs.com/xiaolemc/p/18130150

相关文章

  • 树链剖分 学习笔记
    随便写一点。1.原理定义重儿子为子树内子树大小最大的任一个点,重边为重儿子向其父亲连的边,其余为轻边。根据定义,轻边的父亲的子树大小一定不小于这个点的子树大小的二倍。又可以证出重边数量是\(O(\logn)\)的。因此可以用线段树维护这个东西。2.应用2.1dsu2.2lca考......
  • 点分治学习笔记
    前置知识:树的重心对于一颗无根树上的每一个点,计算其所有子树中最大的子节点数,这个值最小的点就是树的重心1.定义点分治,又叫树分治,点分治是一种在树上进行路径静态统计的算法,所谓树上的静态统计,并不是像树剖一样维护路径最值,路径之和一类的统计,点分治的本质其实是将一棵树拆分......
  • 小熊派BearPi-HM_nano开发笔记及避坑
    小熊派BearPi-HM_nano开发笔记及避坑前排提示:直接使用官方提供的Ubuntu18.04OVF,自己配有诸多问题,PPT未给出详细方案。即使是用虚拟机OVF,也有不少坑,现记录如下:基本配置问题1:Certificateverificationfailed:ThecertificateisNOTtrusted执行sudoaptupdate时提示“Cert......
  • 图论杂题
    Codeforces1572D-BridgeClub题意给出\(n\),有\(2^n\)个点,点权已给出。要求只有两个点的编号的二进制上有且只有一个位置不同时,这两个点有连边。求原图最多选择\(k\)条边的最大(点)权匹配。\(n\le20;k\le100\)Sol考虑边连接的两个点的\(\mathrm{popcount}\)一定不......
  • 个人博客项目笔记_07
    写文章写文章需要三个接口:获取所有文章类别获取所有标签发布文章1.所有文章分类1.1接口说明接口url:/categorys请求方式:GET请求参数:参数名称参数类型说明返回数据:{"success":true, "code":200,"msg":"success",......
  • tracer ftrace笔记(23)—— 上层trace打印流程-TODO
    1.ATRACE_INT打印不出来分析#defineATRACE_INT(name,value)atrace_int(ATRACE_TAG,name,value)///system/core/libcutils/include/cutils/trace.hstaticinlinevoidatrace_int(uint64_ttag,constchar*name,int32_tvalue){ if(CC_UNLIKELY(atrace_is_tag_enabl......
  • 个人博客项目笔记_06
    Bug修正之前Article中的commentCounts,viewCounts,weight字段为int,会造成更新阅读次数的时候,将其余两个字段设为初始值0。处理办法:将int改为Integerpackagecom.cherriesovo.blog.dao.pojo;importlombok.Data;@DatapublicclassArticle{publicstaticfinalintA......
  • Selenium 笔记
    相关资料Selenium官网Selenium文档SeleniumPython接口文档如果要查看其他语言的Selenium接口文档,见下载SeleniumW3CWebDriver规范Web驱动器可以访问Selenium官方Web驱动器生态查看各主流浏览器的Web驱动器下载Chrome也包含了ChromeDriver文档115以后版本115以......
  • 苍穹外卖学习笔记——第四天
    套餐管理新增套餐需求分析和设计产品原型新增套餐添加菜品窗口业务规则套餐名称唯一。套餐必须属于某个分类。套餐必须包含菜品。名称、分类、价格、图片为必填项。添加菜品窗口需要根据分类类型来展示菜品。新增的套餐默认为停售状态。接口设计根据类型查询分......
  • 强化学习-DQN改进及一些强化学习路由优化论文笔记
    RL通用超参数DQN改进DuelStructureVS→该state在当前policy下的valueQSA→该state进行这个action在当前policy下的valueadvantage=VS-QSA裁剪区域的确定?34194按行输出min,33193min为90*90Replaybufferbackgroundknowledge[bisectModule]python自带的二......