倍增及其应用

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];

模版题:P3379 【模板】最近公共祖先(LCA)

//倍增法求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;
    

以上是关于倍增及其应用的主要内容,如果未能解决你的问题,请参考以下文章

P3379 模板最近公共祖先(LCA)(倍增LCA)

[luogu3379]最近公共祖先(树上倍增求LCA)

倍增法求LCA

倍增求LCA

树,LCA,最近公共祖先,倍增

lca(最近公共祖先(在线)) 倍增法详解