【Ybt OJ】[数据结构 第5章] 倍增(LCA) [前半章]

45 篇文章 0 订阅
7 篇文章 0 订阅

「 「 数据结构 」 」 5 5 5章 倍增问题 ( ( ( 3 3 3 ) ) )
目录:

A.查找编号
B.开车旅行
C.树上距离

A . A. A. 例题 1 1 1 查找编号

在这里插入图片描述
洛谷 l i n k link link

分析:

直接 l o w e r lower lower_ b o u n d ( ) bound() bound()就搞完了
也可以倍增 比它小就一直跳 最后输出倍增到的位置 − 1 -1 1

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define reg register
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,m,a[N];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	while(m--)
	{
		int x,p=0;
		scanf("%d",&x);
		for(int i=20;i>=0;i--)
			if(p+(1<<i)<=n)
			if(a[p+(1<<i)]<x) 
				p+=(1<<i);  //倍增跳小于当前数
		if(a[p+1]==x&&p<=n) 
			printf("%d ",p+1);
		else printf("-1 ");
	} 
	
	return 0;
} 

B . B. B. 例题 2 2 2 开车旅行

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
洛谷 l i n k link link

分析:

做着做着 这题就紫掉蓝了。。
模拟 + + +倍增 细节也挺多

用链表两边拓展 找到最近的两个 再从链表删除当前点
这样很慢 那倍增就好了 但两个人是交替走的
就可以用 f 0 / 1 , s t , k f_{0/1,st,k} f0/1,st,k 表示第一步是 A / B A/B A/B走 起点是 s t st st 2 k 2^k 2k能到达的地方
求距离也同时用 d i s 0 / 1 , s t , k dis_{0/1,st,k} dis0/1,st,k记录
第一问就直接找最小比值 第二问就是倍增 累计 A / B A/B A/B距离

一开始我第一问一直 n t nt nt 打成 ( A / B ) × 1.0 (A/B)\times1.0 (A/B)×1.0 ( ( (这些都是除号 ) ) ) 后面改成 A / B × 1.0 A/B\times1.0 A/B×1.0 但输出不对
然后找了题解的标来改 发现要改成 1.0 × A / B 1.0\times A/B 1.0×A/B 就过样例了 但还是 W A WA WA
结果找最小那里 要先判断 B B B走的距离 > 0 >0 >0 然后就过了 因为题目:
在这里插入图片描述

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e5+5;
struct node{
	int x,id;
}a[N];
bool cmp(node x,node y){return x.x<y.x;}
int n,m,pre[N],nxt[N],ans,loc[N],f[N][2][21];
ll dis[N][2][21],A,B,T;
db minn=2147483647;
bool Com(int p,int l,int r)
{
	if(!l) return 0;
	if(!r) return 1;
	return a[p].x-a[l].x<=a[r].x-a[p].x?1:0;  //找最近
}
int Scom(int p,int l,int r)
{
	if(!l) return a[r].id;
	if(!r) return a[l].id;
	return a[p].x-a[l].x<=a[r].x-a[p].x?a[l].id:a[r].id;  //找第二近
}
void go_step1()  //走第一步
{
	for(int i=1;i<=n;i++)
	{
		loc[a[i].id]=i;
		pre[i]=i-1;
		nxt[i]=i+1;
	}
	pre[1]=nxt[n]=0;
	for(int i=1;i<=n;i++)
	{
		int p=loc[i],l=pre[p],r=nxt[p];
		if(Com(p,l,r)){
			f[i][1][0]=a[l].id;
			f[i][0][0]=Scom(p,pre[l],r);
		}else{
			f[i][1][0]=a[r].id;
			f[i][0][0]=Scom(p,l,nxt[r]);
		}
		//f[i][0][0]=Com(p,l,r)?Scom(p,pre[l],r):Scom(p,l,nxt[r]);
		if(l) nxt[l]=r;
		if(r) pre[r]=l;
	}
}
void go_step2()  //先小A再小B
{
	for(int i=1;i<=n;i++)
	{
		f[i][0][1]=f[f[i][0][0]][1][0];
		dis[i][0][1]=abs(a[loc[i]].x-a[loc[f[i][0][0]]].x);
		dis[i][1][1]=abs(a[loc[f[i][0][1]]].x-a[loc[f[i][0][0]]].x);
	}
}
void drive()  //倍增正常走
{
	for(int j=2;j<=20;j++)
		for(int i=1;i<=n;i++)
		{
			f[i][0][j]=f[f[i][0][j-1]][0][j-1];
			dis[i][0][j]=dis[i][0][j-1]+dis[f[i][0][j-1]][0][j-1];
			dis[i][1][j]=dis[i][1][j-1]+dis[f[i][0][j-1]][1][j-1];
		}
}
void ABstep(int st,ll x)  //看倍增走到哪里
{
	A=B=0;
	for(int i=20;i>=1;i--)
		if(f[st][0][i]&&A+B+dis[st][0][i]+dis[st][1][i]<=x)
		{
			A+=dis[st][0][i];
			B+=dis[st][1][i];  //分别算贡献
			st=f[st][0][i];
		}
	if(f[st][0][0]&&A+B+dis[st][0][1]<=x) A+=dis[st][0][1];
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].x);
		a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	go_step1();
	go_step2();
	drive();
	scanf("%lld%d",&T,&m);
	for(int i=1;i<=n;i++)
	{
		ABstep(i,T);
		if(B&&1.0*A/B<minn)
		{
			minn=1.0*A/B;
			ans=i;
		}
	}
	printf("%d\n",ans);
	while(m--)
	{
		int st;
		scanf("%d%lld",&st,&T);
		ABstep(st,T);
		printf("%lld %lld\n",A,B);
	}
	return 0;
} 

C . C. C. 例题 3 3 3 树上距离

在这里插入图片描述
在这里插入图片描述

分析:

L C A LCA LCA模板
对于 ( x , y ) (x,y) (x,y)的树上距离
就是 x x x根节点的距离 + y +y +y到根节点的距离 − 2 × ( x , y ) -2\times (x,y) 2×(x,y) L C A LCA LCA到根节点的距离
在这里插入图片描述

比如这幅图中 ( 5 , 6 ) (5,6) (5,6)的树上距离 3 3 3 5 5 5 1 1 1的距离 : 2 + 6 :2+6 :2+6 1 1 1的距离 : 3 − 2 × ( 5 , 6 ) :3-2\times (5,6) :32×(5,6) L C A LCA LCA 2 2 2 1 1 1的距离 : 1 :1 :1
= 2 + 3 − 2 × 1 = 3 =2+3-2\times1=3 =2+32×1=3

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e4+5;
int n,m,head[N],tot,fa[21][N],dis[21][N],dep[N];
struct node{
	int to,next,x;
}a[N<<2];
void add(int x,int y,int k)
{
	a[++tot]=(node){y,head[x],k};
	head[x]=tot;
}
void dfs(int x,int father)
{
	dep[x]=dep[father]+1;
	for(int i=head[x];i;i=a[i].next)
	{
		int qwq=a[i].to;
		if(qwq!=father)
		{
			fa[0][qwq]=x;
			dis[0][qwq]=a[i].x;
			dfs(qwq,x);
		}
	}
}
int lca(int x,int y)
{
	if(dep[y]>dep[x]) swap(x,y);
	for(int i=20;i>=0;i--)
		if(dep[fa[i][x]]>=dep[y])
			x=fa[i][x];
	if(x==y) return x;
	for(int i=20;i>=0;i--)
		if(fa[i][x]!=fa[i][y])
		{
			x=fa[i][x];
			y=fa[i][y];
		}
	return fa[0][x];  //求LCA
}
int query(int x,int y)
{
	int LCA=lca(x,y);
	if(LCA==x) return dis[20][y]-dis[20][x];
	if(LCA==y) return dis[20][x]-dis[20][y];
	return dis[20][x]+dis[20][y]-2*dis[20][LCA];  //求树上距离
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	{
		int x,y,k;
		scanf("%d%d%d",&x,&y,&k);
		add(x,y,k);
		add(y,x,k);
	}
	dfs(1,0);
	for(int i=1;i<=20;i++)
		for(int j=1;j<=n;j++)
		{
			fa[i][j]=fa[i-1][fa[i-1][j]];
			dis[i][j]=dis[i-1][j]+dis[i-1][fa[i-1][j]];
		}
	while(m--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d\n",query(x,y));
	}
	
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值