离线Tarjan算法

离线Tarjan算法

讲解可以看这个文章:最近公共祖先(LCA)算法实现过程 【Tarjan离线+倍增在线+RMQ】,下面是我的模板:

const int N=500000+7;
int pre[N],first[N],first2[N],tot,tot2;
bool vis[N];//标记有没有询问
int n;
struct edge
{
    int v,next;
} e[2*N];
struct Query
{
    int v,w,next;
} query[2*N];
void add_edge(int u,int v)
{
    e[tot].v=v;
    e[tot].next=first[u];
    first[u]=tot++;
}
void add_query(int u,int v)
{
    query[tot2].v=v;
    query[tot2].w=-1;
    query[tot2].next=first2[u];
    first2[u]=tot2++;
}
int find(int x)
{
    return x==pre[x]?x:pre[x]=find(pre[x]);
}
int lca(int u,int fa)
{
    for(int i=first[u]; ~i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==fa) continue;
        lca(v,u);
        pre[v]=u;
    }
    vis[u]=1;
    for(int i=first2[u]; ~i; i=query[i].next)
    {
        int v=query[i].v;
        if(vis[v])
            query[i].w=find(v);
    }
}
void init()
{
    mem(first,-1);
    mem(first2,-1);
    mem(vis,0);
    tot=0;
    tot2=0;
    for(int i=1; i<=n; i++)
        pre[i]=i;
}
int main()
{
    int m,s,u,v;
    scanf("%d%d%d",&n,&m,&s);
    init();
    for(int i=1; i<n; i++)
    {
        scanf("%d%d",&u,&v);
        add_edge(u,v);
        add_edge(v,u);
    }
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&u,&v);
        add_query(u,v);
        add_query(v,u);
    }
    lca(s,pre[s]);
    for(int i=0; i<tot2; i++)
        if(query[i].w!=-1)
            printf("%d\n",query[i].w);
    return 0;
}

HDU2586 How far away ?(最近公共祖先lca,离线Tarjan,最短路)

有n个点,n-1条边,给出了m组询问,求的是每一组询问的两个点的距离是多少。

我们可以采用离线Tarjan算法。

用dis[i]表示从根节点到当前节点的距离,然后求每组询问 的最近公共祖先,比如询问i,j两点,那么计算出:

dis[i]+dis[j]-2*dis[他们的公共祖先],就是要求的距离了

using namespace std;  
typedef long long ll;  
#define inf 1000000  
#define mem(a,b) memset(a,b,sizeof(a))  
const int N=100000+7;  
const int M=2*N;  
int pre[N],first[N],first2[N],tot,tot2;  
bool vis[N];//标记有没有询问  
int n;  
int fa[N],ans[N],cnt;  
int vis2[N],dis[N];  
map<string,int>mp;  
struct edge  
{  
    int v,next,w;  
} e[M];  
struct Query  
{  
    int v,next,id;  
} query[M];  
void add_edge(int u,int v,int w)  
{  
    e[tot].v=v;  
    e[tot].w=w;  
    e[tot].next=first[u];  
    first[u]=tot++;  
}  
void add_query(int u,int v,int id)  
{  
    query[tot2].id=id;  
    query[tot2].v=v;  
    query[tot2].next=first2[u];  
    first2[u]=tot2++;  
}  
int find(int x)  
{  
    return x==pre[x]?x:pre[x]=find(pre[x]);  
}  
void lca(int u,int fa)  
{  
    for(int i=first[u]; ~i; i=e[i].next)  
    {  
        int v=e[i].v;  
        if(v==fa) continue;  
        lca(v,u);  
        pre[v]=u;  
    }  
    vis[u]=1;  
    for(int i=first2[u]; ~i; i=query[i].next)  
    {  
        int v=query[i].v;  
        if(vis[v])  
        {  
            int id=query[i].id;  
            ans[id]=dis[u]+dis[v]-2*dis[find(v)];  
        }  
    }  
}  
void dfs(int u,int len)  
{  
    vis2[u]=1;  
    dis[u]=len;  
    for(int i=first[u]; ~i; i=e[i].next)  
    {  
        int v=e[i].v,w=e[i].w;  
        if(!vis2[v])  
            dfs(v,len+w);  
    }  
}  
void init()  
{  
    mem(first,-1);  
    mem(first2,-1);  
    mem(vis,0);  
    mem(vis2,0);  
    mem(fa,-1);  
    mem(ans,0);  
    tot=0;  
    tot2=0;  
    cnt=1;  
    mp.clear();  
    for(int i=1; i<=n; i++)  
        pre[i]=i;  
}  
int main()  
{  
    int t,m;  
    int u,v,w;  
    scanf("%d",&t);  
    while(t--)  
    {  
        scanf("%d%d",&n,&m);  
        init();  
        for(int i=1; i<n; i++)  
        {  
            scanf("%d%d%d",&u,&v,&w);  
            add_edge(u,v,w);  
            add_edge(v,u,w);  
        }  
        for(int i=1; i<=m; i++)  
        {  
            scanf("%d%d",&u,&v);  
            add_query(u,v,i);  
            add_query(v,u,i);  
        }  
        dfs(1,0);  
        lca(1,1);  
        for(int i=1; i<=m; i++)  
            printf("%d\n",ans[i]);  
    }  
    return 0;  
}

results matching ""

    No results matching ""