参考文章: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;
}