【模板】LCA(倍增)

 

边带权的LCA

使用方法:

  • 存边请使用链式前向星(head+nxt+ver+val 详见最下)
  • 宏定义中的MAXN为点数
  • 宏定义中的MAXST为点数以2为底的对数
  • 宏定义中的INIT为权值的初值(算路径权值和设为0,路径权值最小值设为INF)
  • 宏定义中的max后面为权值转化的函数(路径权值最小值设为min,权值路径和请自己定义)
namespace LCA {
	#define max min
	#define MAXN 500001
	#define MAXST 20
	#define INIT 0x7fffffff
	int fa_lca[MAXN][MAXST];
	int val_lca[MAXN][MAXST];
	int dep[MAXN];
	int lg[MAXN];
	void dfs(int p,int dp,int f,int v) {
		dep[p]=dp;
		fa_lca[p][0]=f;
		val_lca[p][0]=v;
		for(int i=1;i<=lg[dp];i++)
			fa_lca[p][i]=fa_lca[fa_lca[p][i-1]][i-1],
			val_lca[p][i]=max(val_lca[p][i-1],val_lca[fa_lca[p][i-1]][i-1]);
		for(int i=head[p];i;i=nxt[i])
			if(ver[i]!=f)dfs(ver[i],dp+1,p,val[i]);
	}
	void init(int a,int n) {
		lg[1]=0;
		for(int i=2;i<=n;i++)
			lg[i]=lg[i/2]+1;
		dfs(a,1,a,0);
	}
	pair<int,int> query(int x,int y) {
		int ans=INIT;
		while(dep[x]!=dep[y]) {
			if(dep[x]>dep[y]) {
				ans=max(ans,val_lca[x][lg[dep[x]-dep[y]]]);
				x=fa_lca[x][lg[dep[x]-dep[y]]];
			}
			else {
				ans=max(ans,val_lca[y][lg[dep[y]-dep[x]]]);
				y=fa_lca[y][lg[dep[y]-dep[x]]];
			}
		}
		if(x==y)return make_pair(x,ans);
		for(int i=lg[dep[x]];i>=0;i--)
			if(fa_lca[x][i]!=fa_lca[y][i]) {
				ans=max(ans,val_lca[x][i]);
				x=fa_lca[x][i];
				ans=max(ans,val_lca[y][i]);
				y=fa_lca[y][i];
			}
		ans=max(ans,max(val_lca[x][0],val_lca[y][0]));
		return make_pair(fa_lca[x][0],ans);
	}
	#undef max
	#undef MAXN
	#undef MAXST
	#undef INIT
}
int head[500001]={0},nxt[1000001],ver[1000001],val[1000001],tot=0;
void add(int x,int y,int v) {
	ver[++tot]=y,val[tot]=v,nxt[tot]=head[x],head[x]=tot;
	ver[++tot]=x,val[tot]=v,nxt[tot]=head[y],head[y]=tot;
}

 

转载于:https://www.cnblogs.com/akakw1/p/9755490.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值