区间最值与lca问题

1.区间最值st表

st表的修改复杂度O ( nlogn ),查询复杂度O(1),适合解决修改很少,询问很多的区间最值问题

其中,st表建表过程如下,记f[i][j]表示从i个位置开始长度为2^{^{^{j}}}的区间最值,则f[i][0]=a[i],即f[i][2_{_{}}^{0}{}]=a[i]

void build(){
	for(int i=1;i<=30;i++){//2的阶
		for(int j=1;j<=n;j++)
		{
			f[j][i][0]=f[j][i-1][0];//上一个长度2^i-1
			f[j][i][1]=f[j][i-1][1];
			if(j+k<=n){
				f[j][i][0]=max(f[j][i][0],f[j+k][i-1][0]);//倍增不越界,获取更小长度
				f[j][i][1]=min(f[j][i][1],f[j+k][i-1][1]);
			}  
			
		}
		k*=2;
	}
}

修改时,区间[L,L+2{_{}}^{k}-1]与区间[R+1-2{_{}}^{k},R]能覆盖区间[L,R],其中,记k=log(r-l+1+0.5)/log(2)

int get_max(int l,int r){
	int len=(r-l+1);
	int k=(log(len+0.5)/log(2));
	return max(f[l][k][0],f[r+1-(1<<k)][k][0]);
}
2.lca问题

lca可实现O(logn)的求出两点的最近公共祖先,用倍增方式,借用RMQ思想,建图如下

void dfs(int x,int fa){
	dep[x]=dep[fa]+1;
	f[x][0]=fa;
	h[x]=h[fa]+1;
	for(int i=1;i<=lg[dep[x]];i++)
	  f[x][i]=f[f[x][i-1]][i-1];
	for(int i:v[x]){
		if(i==fa)  continue;
		dfs(i,x);
	}
}

其中f[x][i]=f[f[x][i-1]][i-1]表示x的两个儿子倍增从2_{}^{j-1}跳至2_{}^{j}

计算部分,先将高度较大的x跳至y的最近距离,后x与y在不相等下一起跳,知道他们的父亲为lca返回父亲f[x][0]

int get_lca(int x,int y){
//	if(dep[x]<dep[y])  swap(x,y);
//	while(dep[x]>dep[y])  //x处在下面 
//	  x=f[x][lg[dep[x]-dep[y]]-1];
//	if(x==y)  return x;
//    //两侧跳lca
//	for(int k=lg[dep[x]]-1;k>=0;k--)
//	  if(f[x][k]!=f[y][k]){
//	  	x=f[x][k];y=f[y][k];
//	  } 
//	if(x==y)  return x;
//	return f[x][0];
    if(dep[x]<dep[y])  swap(x,y);
    for(int i=lg[dep[x]]-1;i>=0;i--)
      if(dep[f[x][i]]>dep[f[y][i]])
        x=f[f[x][i-1]][i-1];  //x往上跳
    if(x==y)  return x;
    for(int i=lg[dep[x]]-1;i>=0;i--)
      if(f[x][i]!=f[y][i])
        x=f[x][i],y=f[y][i];//在同一深度,一起跳
    if(x==y)  return x;
    return f[x][0];
}

计算树上两点之间的距离公式h[x]+h[y]-(h[get_lca(x,y)]<<1);其中,h[i]表示i号点到根节点距离,若两条树上最短路相交,则dis(a,b)+dis(c,d)>=dis(a,c)+dis(b,d),这条路径总和一定大于等于起点的距离,终点的距离和

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值