洛谷上的lca模板题——传送门

学了求lca的tarjan算法(离线),在洛谷上做模板题,结果后三个点超时。

又把询问改成链式前向星,才ok。

这个博客,tarjan分析的很详细。

附代码——

#include <cstdio>
#include <cstring>

const int maxn = 500001;

int n, m, cnt, s, cns;
int x, y, z[maxn];//z是x和y的lca 
int f[maxn], head[maxn], from[maxn];
bool vis[maxn];
struct node
{
    int to, next;
}e[2 * maxn];
struct Node
{
    int to, next, num;
}q[2 * maxn];

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 - '0';
        ch = getchar();
    }
    return x * f;
}

inline void ask(int u, int v, int i)//储存待询问的结构体,也是链式前向星优化 
{
    q[cns].num = i;//num表示第几次询问 
    q[cns].to = v;
    q[cns].next = from[u];
    from[u] = cns++;
}

inline void add(int u, int v)//
{
    e[cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt++;
}

inline int find(int a)
{
    return a == f[a] ? a : f[a] = find(f[a]);//路径压缩优化 
}

/*inline void Union(int a, int b)
{
    int fx = find(a), fy = find(b);
    if(fx == fy) return;
    f[fy] = fx;
}*/

inline void tarjan(int k)
{
    int i, j;
    vis[k] = 1;
    f[k] = k;
    for(i = head[k]; i != -1; i = e[i].next)
     if(!vis[e[i].to])
     {
          tarjan(e[i].to);
          //Union(k, e[i].to);
          f[e[i].to] = k;
     }
    for(i = from[k]; i != -1; i = q[i].next)
     if(vis[q[i].to] == 1)
      z[q[i].num] = find(q[i].to);
}

int main()
{
    int i, j, u, v;
    n = read();
    m = read();
    s = read();
    memset(head, -1, sizeof(head));
    memset(from, -1, sizeof(from));
    for(i = 1; i <= n - 1; i++)
    {
        u = read();
        v = read();
        add(u, v);//注意添加两遍 
        add(v, u);
    }
    for(i = 1; i <= m; i++)
    {
        x = read();
        y = read();
        ask(x, y, i);//两遍 
        ask(y, x, i);
    }
    tarjan(s);
    for(i = 1; i <= m; i++) printf("%d\n", z[i]);
    return 0;
}
View Code

相关文章: