倍增小分析
2026-06-24 19:27:15
发布于:上海
这里会简单介绍一下倍增的两个模板。
倍增:倍增只是一个实用工具。它的作用是:当你多次在一个大范围内找你想要的某个东西,逐个遍历的时间复杂度很高。这个时候你用倍增,它会用的时间复杂度将小的区间拼成大的区间,再用大大小小的区间帮你用的时间复杂度找到你想要的一个东西。
想必你听不懂。没关系。
倍增的其中一个原理是:二进制。一个整数可以被几个二的次幂拼接而成。(据说是有次幂倍增,但我也不知道怎么个倍法)
倍增可以在数组中进行,也可以在树上进行。
一. 树上倍增-LCA
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
vector<int>v[N];
int deep[N],f[N][25];
void dfs(int x,int y){
deep[x]=deep[y]+1;
f[x][0]=y;
for(int i=1;i<20;i++){//为什么是20?2^20大概是2e6,题目给出的数据范围是5e5
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=0;i<v[x].size();i++){
int to=v[x][i];
if(to!=y)dfs(to,x);
}
return;
}
int lca(int a,int b){
if(deep[a]<deep[b])swap(a,b);//需要深度大的那个一格格往上跳,这边默认a是深度大的。
int len=deep[a]-deep[b];
for(int i=0;i<20;i++){
if((len>>i)&1)a=f[a][i];
}
if(a==b)return a;
for(int i=19;i>=0;i--){
if(f[a][i]==f[b][i])continue;
//为什么continue?因为这里有可能是最近公共祖先祖先或者0或者LCA上面的某个节点
a=f[a][i];
b=f[b][i];
}
return f[a][0];
//为什么是f[a][0],因为拼积木拼到最后肯定会只剩它一块。
}
int main(){
int n,m,s;
cin>>n>>m>>s;
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
v[x].push_back(y);
v[y].push_back(x);
}
dfs(s,0);
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
cout<<lca(x,y)<<'\n';
}
return 0;
}
二.RMQ
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N],f[N][20];
//这边的f[i][j]定义比较特殊:从第i位开始到第i+2^j -1位中最大的
inline int read()
{
//一个快速输入
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int main(){
int n,m;
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read(),f[i][0]=a[i];
for(int k=1;k<20;k++){
for(int i=1;i<=n;i++){
if(i+(1<<k)-1>n)continue;
//大了就continue,不然会RE(空间朝鲜)
f[i][k]=max(f[i][k-1],f[i+(1<<(k-1))][k-1]);
}
}
for(int i=1;i<=m;i++){
int x,y;
x=read(),y=read();
int len=log2(y-x+1);
cout<<max(f[x][len],f[y-(1<<len)+1][len])<<'\n';
//从头开始往后走+从后开始往前走
}
return 0;
}
这里空空如也
















有帮助,赞一个