LCA 离线targin模板

参考文章:https://www.cnblogs.com/jsawz/p/6723221.html

模板题目:POJ1330   有根树 节点1W,查询1次 , 耗时:282ms

//targin 模板 2018.5.8 
#include<stdio.h>
#include<memory.h>
#include<set>
using namespace std;
const int maxn = 10000+10;//一共有多少个节点 
const int maxm = 20000+10;//一共有多少条边
struct Node
{
    int to;
    int next;
    int lca;    
};
Node qedge[4];//要查询的边
Node edge[maxm];//存放顶点的邻接表
int n,m,q;//顶点数,边数 查询数 
int head[maxn],qhead[maxn];//head记录顶点i的第一条边的位置,qhead记录相关查询的第一条边的位置 
int edgeNum,qedgeNum; //树的边数 edgeNum ,查询的数目qedgeNum 
int f[maxn],visit[maxn];//并查集要用到的数组
set<int>s;//找出根节点要用到的集合
void add_edge(int from,int to)
{
    edge[++edgeNum].next = head[from];
    edge[edgeNum].to = to;
    head[from] = edgeNum;
}
void add_qedge(int from,int to)
{
    qedge[++qedgeNum].next = qhead[from];
    qedge[qedgeNum].to = to;
    qhead[from] = qedgeNum;
}
int find(int x) //查询父节点
{
    if(f[x]!=x)
    {
        f[x] = find(f[x]);
    }
    return f[x];
}
void targin(int u)
{
    f[u] = u;
    visit[u] = 1;
    for(int k = head[u] ; k ; k = edge[k].next)//遍历顶点u的邻接表
    {
        if(visit[edge[k].to]==1)
        {
            continue;
        }
        targin(edge[k].to);
        f[edge[k].to] = u;//合并
    }
    for(int k=qhead[u] ; k ; k = qedge[k].next)//找有关顶点u的查询 
    {
        if(visit[qedge[k].to]==1)//另外一个节点已经求出来了
        {
            qedge[k].lca = find(qedge[k].to);
            
            if(k%2==1)
            {
                qedge[k+1].lca = qedge[k].lca;
            }else{
                qedge[k-1].lca = qedge[k].lca;
            }
        }
    }
}
void init() //初始化
{
    s.clear();
    edgeNum = qedgeNum = 0;
    for(int i=1;i<=n;i++)
    {
        visit[i] = 0;
        head[i] = 0;
        qhead[i] = 0;
        s.insert(i);
    }
}
int main()
{
    int t;
    scanf("%d",&t);//测试数
    while(t--)
    {
        scanf("%d",&n);
        init();//初始化 
        m = n -1;  //题目说了,边数m = 顶点数-1
        q = 1;     //题目说了,查询数目 只有1 个
        qedgeNum = edgeNum = 0;
        for(int i=1;i<=m;i++)//输入边数 
        {
            int from,to;
            scanf("%d %d",&from,&to);
            s.erase(to);
            add_edge(from,to);
            add_edge(to,from);
        }
        for(int i=1;i<=q;i++)
        {
            int from,to;
            scanf("%d %d",&from,&to);
            add_qedge(from,to);
            add_qedge(to,from);
        }
        targin(*s.begin());//以该点作为根节点 
        for(int i=1;i<=q;i++) 
        {
            printf("%d\n",qedge[i*2].lca);
        }
    }
    return 0;
}

 

hdu 2586   无根 ,节点4W,查询200  耗时:46ms

 

//targin 模板 2018.5.8 
#include<stdio.h>
#include<memory.h>
const int maxn = 40000+10;//一共有多少个节点 
const int maxm = 80000+10;//一共有多少条边
struct Node
{
    int from;
    int to;
    int next;
    int lca;    
    int len; 
};
Node qedge[200*2+10];//要查询的边
Node edge[maxm];//存放树的边
int n,m,q;//顶点数,边数 查询数 
int head[maxn],qhead[maxn];//记录顶点i的第一条边的位置,和相关查询的第一条边的位置 
int edgeNum,qedgeNum; //树的边数 edgeNum ,查询的数目qedgeNum 
int f[maxn],visit[maxn];
int d[maxn];
void add_edge(int from,int to,int len)
{
    edge[++edgeNum].next = head[from];
    edge[edgeNum].to = to;
    edge[edgeNum].len = len;
    head[from] = edgeNum;
}
void add_qedge(int from,int to)
{
    qedge[++qedgeNum].next = qhead[from];
    qedge[qedgeNum].from = from;
    qedge[qedgeNum].to = to;
    qhead[from] = qedgeNum;
}
int find(int x)
{
    if(f[x]!=x)
    {
        f[x] = find(f[x]);
    }
    return f[x];
}
void targin(int u)
{
    f[u] = u;
    visit[u] = 1;
    for(int k = head[u] ; k ; k = edge[k].next)
    {
        if(visit[edge[k].to]==1)
        {
            continue;
        }
        d[edge[k].to] = d[u] + edge[k].len;
        targin(edge[k].to);
        f[edge[k].to] = u;//合并
    }
    for(int k=qhead[u] ; k ; k = qedge[k].next)//找有关顶点u的查询 
    {
        if(visit[qedge[k].to]==1)// 
        {
            qedge[k].lca = find(qedge[k].to);
            
            if(k%2==1)
            {
                qedge[k+1].lca = qedge[k].lca;
            }else{
                qedge[k-1].lca = qedge[k].lca;
            }
        }
    }
}
void init()
{
    edgeNum = qedgeNum = 0;
    for(int i=1;i<=n;i++)
    {
        visit[i] = 0;
        head[i] = 0;
        qhead[i] = 0;
        d[i] = 0;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&q); //输入节点数,输入边数,输入查询数 
        init();//初始化 
        m = n-1;
        qedgeNum = edgeNum = 0;
        for(int i=1;i<=m;i++)//输入边数 
        {
            int from,to,len;
            scanf("%d %d %d",&from,&to,&len);
            add_edge(from,to,len);
            add_edge(to,from,len);
        }
        for(int i=1;i<=q;i++)
        {
            int from,to;
            scanf("%d %d",&from,&to);
            add_qedge(from,to);
            add_qedge(to,from);
        }
        targin(1);//以1作为根节点 
//        for(int i=1;i<=n;i++)
//        {
//            printf("%d ",visit[i]);
//        }
//        printf("\n");
        for(int i=1;i<=q;i++)
        {
            int from,to,lca;
            from = qedge[i*2].from;
            to = qedge[i*2].to;
            lca = qedge[i*2].lca;
             
            printf("%d\n",d[from]+d[to]-2*d[lca]);
        }
    }
    return 0;
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值