bryce1010专题训练——LCA

1、Targan算法(离线)

http://poj.org/problem?id=1470

/*伪代码
Tarjan(u)//marge和find为并查集合并函数和查找函数
{
    for each(u,v)    //访问所有u子节点v
    {
        Tarjan(v);        //继续往下遍历
        marge(u,v);    //合并v到u上
        标记v被访问过;
    }
    for each(u,e)    //访问所有和u有询问关系的e
    {
        如果e被访问过;
        u,e的最近公共祖先为find(e);
    }
}

*/
//思想
/*
1.任选一个点为根节点,从根节点开始。
2.遍历该点u所有子节点v,并标记这些子节点v已被访问过。
3.若是v还有子节点,返回2,否则下一步。
4.合并v到u上。
5.寻找与当前点u有询问关系的点v。
6.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点a。
*/

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<math.h>
using namespace std;
#define ll long long


const int MAXN=1010;
const int MAXQ=500010;

//并查集部分
int F[MAXN];//初始化为-1
int find(int x)
{
    if(F[x]==-1)return x;
    return F[x]=find(F[x]);
}
//merge
void bing(int u,int v)
{
    int t1=find(u);
    int t2=find(v);
    if(t1!=t2)
    {
        F[t1]=t2;
    }
}
//****************
//建图部分
bool vis[MAXN];
int ancestor[MAXN];//存储查询过程节点的祖先
struct Edge
{
    int to,next;
}edge[MAXN<<2];
int head[MAXN],tot;
void add_edge(int u,int v)
{
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}

//离线查询部分

struct Query
{
    int q,next;
    int index;// 查询编号
}query[MAXQ<<1];

int answer[MAXQ];//存储最后的每个查询的公共祖先,下标0,Q-1
int h[MAXQ];
int tt;int Q;

void add_query(int u,int v,int index)
{
    query[tt].q=v;
    query[tt].next=h[u];
    query[tt].index=index;
    h[u]=tt++;
    query[tt].q=u;
    query[tt].next=h[v];
    query[tt].index=index;
    h[v]=tt++;
}

//LCA部分
void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
    tt=0;
    memset(h,-1,sizeof(h));
    memset(vis,false,sizeof(vis));
    memset(F,-1,sizeof(F));
    memset(ancestor,0,sizeof(ancestor));
}

void LCA(int u)
{
    ancestor[u]=u;
    vis[u]=true;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(vis[v])continue;
        LCA(v);
        bing(u,v);
        ancestor[find(u)]=u;//?
    }
    for(int i=h[u];i!=-1;i=query[i].next)
    {
        int v=query[i].q;
        if(vis[v])
        {
            answer[query[i].index]=ancestor[find(v)];
        }
    }
}

bool flag[MAXN];
int Count_num[MAXN];
int main()
{
    int n;
    int u,v,k;
    while(scanf("%d",&n)==1)
    {
        init();
        memset(flag,false,sizeof(flag));
        for(int i=1;i<=n;i++)
        {
            scanf("%d:(%d)",&u,&k);
            while(k--)
            {
                scanf("%d",&v);
                flag[v]=true;
                add_edge(u,v);
                add_edge(v,u);
            }
        }
        scanf("%d",&Q);
        for(int i=0;i<Q;i++)
        {
            char ch;
            cin>>ch;
            scanf("%d %d)",&u,&v);
            //cin>>ch;
            add_query(u,v,i);
        }
        int root;
        for(int i=1;i<=n;i++)//找到没有入度的点作为root
        {
            if(!flag[i])
            {
                root=i;
                break;
            }
        }
        LCA(root);
        memset(Count_num,0,sizeof(Count_num));
        for(int i=0;i<Q;i++)
        {
            Count_num[answer[i]]++;
        }
        for(int i=1;i<=n;i++)
        {
            if(Count_num[i]>0)
            {
                printf("%d:%d\n",i,Count_num[i]);
            }
        }
    }
//    getchar();getchar();
    return 0;
}



/*
5
5:(3) 1 4 2
1:(0)
4:(0)
2:(1) 3
3:(0)
6
(1 5) (1 4) (4 2) (2 3) (1 3) (4 3)
*/

2.带边权的Targan离线算法

http://acm.hdu.edu.cn/showproblem.php?pid=2586

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int MAXN=40010;
const int MAXQ=40010;

int n;
//并查集部分
int F[MAXN];//初始为-1
int find(int x)
{
    if(F[x]==-1)return x;
    return F[x]=find(F[x]);
}

int bing(int u,int v)
{
    int t1=find(u);
    int t2=find(v);
    if(t1!=t2)
    {
        F[t1]=t2;
    }
}


//建图部分
bool vis[MAXN];
int ancestor[MAXN];
struct Edge
{
    int to,next;
    int val;//每条边的权重
}edge[MAXN<<2];
int head[MAXN],tot;//head初始为-1

void add_edge(int u,int v,int val)
{
    edge[tot].next=head[u];
    edge[tot].to=v;
    edge[tot].val=val;
    head[u]=tot++;
//    edge[tot].next=head[v];
//    edge[tot].to=u;
//    edge[tot].val=val;
//    head[v]=tot++;
}
int dist[MAXN];
bool flag[MAXN];
//查询部分
struct Query
{
    int q,next;
    int index;//查询标号
}query[MAXQ<<1];
int answer[MAXQ];//存储每个查询的结果
int h[MAXQ];
int tt;
int Q;
void add_query(int u,int v,int index)
{
    query[tt].next=h[u];
    query[tt].q=v;
    query[tt].index=index;
    h[u]=tt++;
    query[tt].next=h[v];
    query[tt].q=u;
    query[tt].index=index;
    h[v]=tt++;
}



//LCA部分
void init()
{
    tot=0;
    memset(F,-1,sizeof(F));
    memset(vis,false,sizeof(vis));
    memset(ancestor,0,sizeof(ancestor));
    memset(head,-1,sizeof(head));
    memset(h,-1,sizeof(h));
    memset(dist,0,sizeof(dist));
    memset(flag,false,sizeof(flag));
    tt=0;
}
void LCA(int u,int val)
{
    ancestor[u]=u;
    vis[u]=true;
    dist[u]=val;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        int weight=edge[i].val;
        if(vis[v])continue;
        LCA(v,val+weight);
        bing(u,v);
        ancestor[find(u)]=u;
    }
    for(int i=h[u];i!=-1;i=query[i].next)
    {
        int v=query[i].q;
        if(vis[v])
        {
//            cout<<ancestor[find(v)]<<endl;
            answer[query[i].index]=dist[v]+dist[u]-2*dist[ancestor[find(v)]];
        }
    }
}

int root;

int main()
{
    int T,u,v,val;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&Q);
        init();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&val);
            flag[v]=true;
            add_edge(u,v,val);
            add_edge(v,u,val);
        }
        for(int i=0;i<Q;i++)
        {
            scanf("%d%d",&u,&v);
            add_query(u,v,i);
        }
        //找到没有入度的节点作为root
        for(int i=1;i<=n;i++)
            if(!flag[i])
            {
                root=i;
                break;
            }
        LCA(root,0);
        for(int i=0;i<Q;i++)
        {
            printf("%d\n",answer[i]);
        }
    }



}


/*
2
3 2
1 2 10
3 1 15
1 2
2 3

*/










posted @ 2018-07-29 11:49  Bryce1010  阅读(202)  评论(0编辑  收藏  举报