倍增

RMQ问题

我们用 dp[i][j] 表示 [i,i+2j1] 区间的最大值,预处理的时候可以分两个部分进行查询最大值。
image
查询区间 [l,r] 的最大值时我们只用查询 (l,l+2s1)(r2s+1,r) ,其中 s=log2(rl+1) 就可以了,我们保证(l,r)的区间一定能覆盖到且不会超出。
预处理时间复杂度 O(nlogn) ,查询时间复杂度 O(1) .

int a[N],dp[N],n;
void prep(){//预处理
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i][0]=a[i];
}
for(int j=1;(1<<j)<=n;j++){
for(int i=1;i<=n;i++){
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int query(int l,int r){//查询
int k=log2(r-l+1);
return max(dp[l][k],dp[r-(1<<k)+1][k]);
}

LCA

最近公共祖先简称LCA(Lowest Common Ancestor).两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个.
本题考虑倍增,用 fa[x][i] 表示节点 x 的第 2i 个祖先,先使两个节点到达同一深度,然后再同步从上往下跳.

int vis[N],dis[N],f[N][20];
vector<int>g[N];
void dfs(int x,int d){
vis[x]=1;
dis[x]=d;
for(int i=1;(1<<i)<=k;i++){
f[x][i]=f[f[x][i-1]][i-1];
}
for(int v:g[x]){
if(v==fa[x][0]) continue;
fa[v][0]=x;
dfs(v,d+1);
}
}
int lca(int x,int y){
if(dis[y]>dis[x]) swap(x,y);
int k=dis[x]-dis[y];
for(int i=1;(1<<i)<=k;i++){//对于xy距离k进行二进制划分
if(k&(1<<i)) x=fa[x][i];
}
if(x==y) return x;
for(int i=19;i>=0;i--){//从上往下跳,最后一定跳到LCA的下一层
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
}
return fa[x][0];
}
posted @   BSS梅者如西  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
   
点击右上角即可分享
微信分享提示