LCA-RMQ+欧拉序

还是那一道洛谷的板子题来说吧

传送门

其实好几天之前就写了

结果dr实在是太弱了

没有那么多的精力

于是就一直咕咕咕了

今天终于补上来了

LCA概念传送门

RMQ传送门

这个算法是基于RMQ和欧拉序的算法

什么是Rmq?
 
RMQ (Range Minimum/Maximum Query)问题是指:
对于长度为 n的数列A,
回答若干询问RMQ(A,i,j)(i,j<=n),
返回数列A中下标在 i,j里的最小(大)值,
也就是说,RMQ问题是指求区间最值的问题。
解决Rmq问题常用ST算法。
 
ST算法时间复杂度:
 预处理O(nlogn)
 单次查询O(1)
 
欧拉序?
 欧拉序是一种树的遍历顺序,其他还有dfs序, 这些序具有一 定的性质。
 欧拉序是树dfs过程中经过 结点的顺序。
若已1->2->4->5->6->7->3的顺序dfs树

即每经过一次结点就记录一次,

n个结点的树有2n-1个记录

基于Rmq和欧拉序的Lca算法:

 预处理出树的欧拉序,预处理id,vs,depth数组

id[u]表示结点u第一次被访问时的下标,

vs[i]表示欧拉序中第i个结点的编号,

depth[i]表示欧拉序中第i个结点的深度。

假设dfs顺序1->2->4->5->3

 

要求Lca(u,v),例如Lca(4,5),
根据dfs的性质,在第一次访问完结点4及其子树,回溯,
再第一次访问到5的过程中,途中访问过的深度最小的结点必是Lca(4,5)
 
Rmq问题。Lca(u,v)=vs[id[u]<=i<=id[v]中depth[i]最小的i]
(假设id[u]<id[v])
 
 
#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 500005;
const int maxm = 1000005;
int head[maxn],nxt[maxm],to[maxm],cnt;
int id[maxm],vis[maxm],depth[maxm],tot;
int f[maxm][20],lg[maxm];

inline int read()
{
    int sum = 0,p = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
            p = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (sum *= 10)+= ch - '0';
        ch = getchar();
    }
    return sum * p;
}

void add(int x,int y)//链式前向星--加边 
{
    nxt[++cnt] = head[x];
    to[cnt] = y;
    head[x] = cnt;
    return;
}

void dfs(int u,int fa,int dep)
{
    id[u] = ++tot;
    vis[tot] = u;
    depth[tot] = dep;
    for(int i = head[u];i;i = nxt[i])
    {
        int v = to[i];
        if(v == fa)
            continue;
        dfs(v,u,dep+1);
        vis[++tot] = u;
        depth[tot] = dep;
    }
    return;
}

void RMQ()
{
    for(int i = 1;i <= tot;i++)
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
    for(int i = 1;i <= tot;i++)
        f[i][0] = i;
    for(int j = 1;(1 << j) <= tot;j++)
        for(int i = 1;i + (1 << j) - 1 <= tot;i++)
        {
            int a = f[i][j-1];
            int b = f[i + (1 << (j - 1))][j - 1];
            if(depth[a] <= depth[b])
                f[i][j] = a;
            else
                f[i][j] = b;
        }
    return;
}

int    st(int x,int y)
{
    int r = id[x];
    int l = id[y];
    if(r < l)
        swap(r,l);
    int k = lg[r - l + 1] - 1;
    int a = f[l][k];
    int b = f[r - (1 << k) + 1][k];
    if(depth[a] <= depth[b])
        return vis[a];
    else
        return vis[b];
}

int main()
{
    int n = read(),m = read(),s = read();
    int x,y;
    for(int i = 1;i < n;i++)
    {
        x = read(),y = read();
        add(x,y);
        add(y,x);
    }
    dfs(s,0,1); 
    RMQ();
    for(int i = 1;i <= m;i++)
    {
        x = read(),y = read();
        printf("%d\n",st(x,y));
    }
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/darlingroot/p/10612077.html