LCA 离线tarjan算法

对于最近公共祖先问题,我们先来看这样一个性质,当两个节点(u,v)的最近公共祖先是x时,那么我们可以确定的说,当进行后序遍历的时候,必然先访问完x的所有子树,然后才会返回到x所在的节点。这个性质就是我们使用Tarjan算法解决最近公共祖先问题的核心思想。

      同时我们会想这个怎么能够保证是最近的公共祖先呢?我们这样看,因为我们是逐渐向上回溯的,所以我们每次访问完某个节点x的一棵子树,我们就将该子树所有节点放进该节点x所在的集合,并且我们设置这个集合所有元素的祖先是该节点x。那么我们有理由相信, 任何一个不属于已经访问的节点和已经访问的节点的LCA一定是当前这个根节点. 于是我们每次访问完一棵子树, 只需要将子树放进根节点对应的集合即可.


poj 1470 :给出一棵树,给出若干个u,v,然后求出u,v的lca,输出每个点座位lca的次数,

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 100000 + 10;
typedef long long ll;
#define clr(x,y) memset(x,y,sizeof x)
#define INF 0x3f3f3f3f
const ll Mod = 1e9 + 7;
typedef pair<int,int> P;


vector<int>g[maxn],q[maxn];
int ans[maxn],fa[maxn],in[maxn];
bool vis[maxn];
int finds(int x)
{
    return fa[x] == x ? x : (fa[x] = finds(fa[x]));
}
void dfs(int u)
{
    fa[u] = u;
    for(int i = 0;i < g[u].size();i ++)
    {
        int v = g[u][i];
        dfs(v);fa[v] = u;
    }
    vis[u] = true;
    for(int i = 0;i < q[u].size();i ++)
    {
        int v = q[u][i];
        if(vis[v])
        {
            int lca = finds(v);ans[lca] ++;
        }
    }
}
int main()
{
    int n;char s[3];
    while( ~ scanf("%d",&n))
    {
        int root;clr(ans,0);clr(vis,false);clr(in,0);
        for(int i = 1;i <= n;i ++)g[i].clear(),q[i].clear();
        for(int i = 1;i <= n;i ++)
        {
            int x,y;scanf("%d:(%d)",&x,&y);
            for(int j = 1;j <= y;j ++)
            {
                int z;scanf("%d",&z);
                g[x].push_back(z);
                in[z] ++;
            }
        }

        int m;scanf("%d",&m);
        while(m --)
        {
            int x,y;scanf(" (%d%d)",&x,&y);
            q[x].push_back(y);q[y].push_back(x);
        }
        for(int i = 1;i <= n;i ++)if(!in[i]){root = i;break;}
        dfs(root);
        for(int i = 1;i <= n;i ++)
            if(ans[i])printf("%d:%d\n",i,ans[i]);
    }
    return 0;
}

hdu 4547 

题意:两种CD操作,一种是可以直接访问当前目录下的任何一个子目录或者文件,一种是返回上一级。操作次数都为1.

思路:求出lca,进行操作。应为都为查询,所以可以离线。

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
#define clr(x,y) memset(x,y,sizeof x)
#define INF 0x3f3f3f3f
const ll Mod = 1e9 + 7;
typedef pair<int,int> P;


map<string,int>ms;

vector<int>g[maxn];
struct Node
{
    int dir;
    int pos;
    int to;
};
int ans[maxn],lca[maxn];
vector<Node>q[maxn];
int in[maxn],fa[maxn],dep[maxn];
bool vis[maxn];
int finds(int x)
{
    return fa[x] == x ? x : (fa[x] = finds(fa[x]));
}
void dfs(int u,int d)
{
    fa[u] = u;dep[u] = d;
    for(int i = 0;i < g[u].size();i ++)
    {
        int v = g[u][i];
        dfs(v,d + 1);
        fa[v] = u;
    }
    vis[u] = true;
    for(int i = 0;i < q[u].size();i ++)
    {
        Node t = q[u][i];
        if(vis[t.to])
        {
            lca[t.pos] = finds(t.to);
        }
    }
}
int U[maxn],V[maxn];
int main()
{
    ios::sync_with_stdio(false);
    int Tcase;cin >> Tcase;
    while(Tcase --)
    {
        int n,m;cin >> n >> m;
        for(int i = 1;i <= n;i ++)g[i].clear(),q[i].clear();
        ms.clear();int tot = 0;
        clr(in,0);clr(vis,false);clr(lca,0);
        for(int i = 1;i <= n - 1;i ++)
        {
            string A,B;cin >> A >> B;
            if(!ms[A])ms[A] = ++ tot;
            if(!ms[B])ms[B] = ++ tot;
            g[ms[B]].push_back(ms[A]);
            in[ms[A]] ++;
        }
        for(int i = 1;i <= m;i ++)
        {
            string A,B;cin >> A >> B;
            q[ms[A]].push_back((Node){1,i,ms[B]});
            q[ms[B]].push_back((Node){-1,i,ms[A]});
            U[i] = ms[A];V[i] = ms[B];
        }
        for(int i = 1;i <= n;i ++)
        {
            if(!in[i] && !vis[i])
            {
                dfs(i,1);break;
            }
        }
        for(int i = 1;i <= m;i ++)
        {
            ans[i] = 0;
            ans[i] += dep[U[i]] - dep[lca[i]];
            if(V[i] != lca[i])ans[i] ++;
        }
        for(int i = 1;i <= m;i ++)
            cout << ans[i] << endl;
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/xiaolonggezte/article/details/79174518