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