倍增及其应用
Posted KaaaterinaX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了倍增及其应用相关的知识,希望对你有一定的参考价值。
一、倍增思想
·在线性递推复杂度过大的时候,引入倍增思想,只递推状态空间中2的整数次幂位置的状态。
·任何整数都可以表示为若干个2的整数次幂的和。
二、ST表
ST表是用于解决可重复贡献问题的数据结构。
(如区间最值问题)
1、预处理
预处理lg数组,记录
l
o
g
2
N
log_2N
log2N的整数值,避免浮点误差
void init()
lg[0]=0;
for(int i=2;i<=n;i++)
lg[i]=lg[i-1]+(1<<(lg[i-1]+1)==i);
预处理st数组,规定st[i][j]是以i为开头,长度为 2 j 2^j 2j的序列内最大值。
for(int i=1;i<=n;i++)
st[i][0]=a[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=max(st[i][j-1],st[i+(1<<j)][j-1]);
2、查询
和更新st表思想相同,找到包含[l,r]区间内所有元素的两段st表值,再取max即可。
int search(int l,int r)
int k=lg[r-l+1];
int t=max(st[l][k],st[r-(1<<k)+1][k]);
return t;
三、LCA
lca指树上最近公共祖先,求lca可以利用倍增的思想。
1、预处理
dfs这棵树,得到每个节点到根的深度以及预处理倍增祖先。
void dfs(int x,int pre)
dep[x]=dep[pre]+1;
f[x][0]=pre;
for(int i=1;(1<<i)<=N;i++)
f[x][i]=f[f[x][i-1]][i-1];
for(int i=0;i<mp[x].size();i++)
if(mp[x][i]!=pre)dfs(mp[x][i],x);
2、lca查询过程
int lca(int x,int y)
if(dep[x]<dep[y])swap(x,y);
int dx=dep[x]-dep[y];
for(int i=0;(1<<i)<=dx;i++)
if((1<<i)&dx)x=f[x][i];
if(x==y)return x;
if(x!=y)
//一起向上跳
for(int i=log2(N);i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i]; y=f[y][i];//当前祖先不相等,更新x,y
return f[y][0];
//倍增法求lca
const int maxn=5e5+7;
vector<int> mp[maxn];
int dep[maxn];//x节点相对父节点的深度
int f[maxn][30];//f[x][i]=x向上走2^i个节点
int N,M,S;
void dfs(int x,int pre)
dep[x]=dep[pre]+1;
f[x][0]=pre;
for(int i=1;(1<<i)<=N;i++)
f[x][i]=f[f[x][i-1]][i-1];
for(int i=0;i<mp[x].size();i++)
if(mp[x][i]!=pre)dfs(mp[x][i],x);
int lca(int x,int y)
if(dep[x]<dep[y])swap(x,y);
int dx=dep[x]-dep[y];
//cout<<"dx="<<dx<<endl;
for(int i=0;(1<<i)<=dx;i++)
if((1<<i)&dx)x=f[x][i];
if(x==y)return x;
if(x!=y)
//一起向上跳
for(int i=log2(N);i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i]; y=f[y][i];//当前祖先不相等,更新x,y
return f[y][0];
int main()
read(N);read(M);read(S);
for(int i=1;i<=N-1;i++)
int a,b;
read(a);read(b);
mp[a].pb(b);
mp[b].pb(a);
dfs(S,0);
while(M--)
int x,y;
read(x);read(y);
cout<<lca(x,y)<<endl;
以上是关于倍增及其应用的主要内容,如果未能解决你的问题,请参考以下文章