Tarjan_LCA

貌似求LCA使用倍增已经可以应付掉大多数需要LCA的题了..

但是有些时候O(MlogN)的复杂度就不可接受了

Tarjan_LCA对于每个询问采用离线处理

总复杂度为O(M+N)

这个复杂度几乎不可能被卡掉

简单说的话用Tarjan求LCA就是根据后序dfs的框架然后用并查集加持。

具体实现过程参加代码。

用HUD2586作为模板

 1 //HUD 2586 Tarjan_LCA
 2 //by Cydiater
 3 //2016.8.15
 4 #include <iostream>
 5 #include <cstring>
 6 #include <string>
 7 #include <cstdio>
 8 #include <cstdlib>
 9 #include <cmath>
10 #include <ctime>
11 #include <queue>
12 #include <map>
13 #include <iomanip>
14 #include <algorithm>
15 using namespace std;
16 #define ll long long
17 #define up(i,j,n)       for(int i=j;i<=n;i++)
18 #define down(i,j,n)     for(int i=j;i>=n;i--)
19 const int MAXN=1e6+5;
20 const int oo=0x3f3f3f3f;
21 inline int read(){
22       char ch=getchar();int x=0,f=1;
23       while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
24       while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
25       return x*f;
26 }
27 int N,M,LINK[MAXN],len=0,dis[MAXN],fa[MAXN],tol=0,Link[MAXN],g[MAXN],T,ans[MAXN];
28 bool vis[MAXN];
29 struct edge{int y,next,v;}e[MAXN];
30 struct query{int y,next,lca;}q[MAXN];
31 namespace solution{
32       inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;}
33       inline void Insert(int x,int y){q[++tol].next=Link[x];Link[x]=tol;q[tol].y=y;}
34       int get(int k){
35             if(g[k]==k) return k;
36             g[k]=get(g[k]);
37             return g[k];
38       }
39       void dfs(int node,int dist,int father){
40             fa[node]=father;dis[node]=dist;
41             for(int i=LINK[node];i;i=e[i].next)
42                   if(e[i].y!=father)
43                         dfs(e[i].y,dist+e[i].v,node);
44       }
45       void init(){
46             N=read();M=read();
47             up(i,1,N-1){
48                   int x=read(),y=read(),v=read();
49                   insert(x,y,v);
50                   insert(y,x,v);
51             }
52             memset(fa,0,sizeof(fa));
53             memset(dis,0,sizeof(dis));
54             memset(vis,0,sizeof(vis));
55             dfs(1,0,0);
56             up(i,1,M){
57                   int x=read(),y=read();
58                   Insert(x,y);
59             }
60       }
61       void lca(int node){
62             vis[node]=1;g[node]=node;
63             for(int i=LINK[node];i;i=e[i].next)
64                   if(!vis[e[i].y]){
65                         lca(e[i].y);
66                         g[e[i].y]=node;
67                   }
68             for(int i=Link[node];i;i=q[i].next)
69                   if(vis[q[i].y]){
70                         q[i].lca=get(q[i].y);
71                         ans[i]=dis[node]+dis[q[i].y]-2*dis[q[i].lca];
72                   }
73       }
74       void output(){
75             up(i,1,M)printf("%d\n",ans[i]);
76       }
77 }
78 int main(){
79       //freopen("input.in","r",stdin);
80       using namespace solution;
81       T=read();
82       while(T--){
83             tol=0;len=0;
84             memset(Link,0,sizeof(Link));
85             memset(LINK,0,sizeof(LINK));
86             init();
87             lca(1);
88             output();
89       }
90       return 0;
91 }
时间: 2024-11-26 01:32:54

Tarjan_LCA的相关文章

AC日记——货车运输 codevs

3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入描述 Input Description 第一行有两个用一个空格隔开的整数 n,m,表示 A

hud 2586 How far away ?

题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2586 How far away ? Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to

hdu 2586 How far away? (LCA模板)

题意: N个点,形成一棵树,边有长度. M个询问,每个询问(a,b),询问a和b的距离 思路: 模板题,看代码.DFS预处理算出每个结点离根结点的距离. 注意: qhead[maxn],而不是qhead[maxm]. 输出用%I64d,不要用%lld. C++ RE后 尝试用 G++交. 代码: struct node{ int to,w,next,lca; }; int const maxn = 40005; int const maxm = 205; int fa[maxn]; int he

poj 3417 Network (LCA,路径上有值)

题意: N个点,构成一棵树.给出这棵树的结构. M条边,(a1,b1)...(am,bm),代表给树的这些点对连上边.这样就形成了有很多环的一个新”树“. 现在要求你在原树中断一条边,在M条边中断一条边,使得新”树“被分成两个部分. 问有多少种方案. 思路: 连上某条新边(a,b),则必定形成一个环.环的路径是a->...->lca(a,b)->...->b,给这些边的值都加1 . 分情况: 在原树中,若一条边的值>=2,去掉这条边,再去掉M条边中的一条,不影响原树的连通性.

LCA 各种神奇的LCA优化方法

LCA(Least Common Ancestors) 树上问题的一种. 朴素lca很简单啦,我就不多说了,时间复杂度n^2 1.倍增LCA 时间复杂度 nlongn+klogn 其实是一种基于朴素lca的优化方法, 朴素lca只能一层层的向上查询,而这个有一定状态压缩的想法 即每一次跳2^i层,让O(n)的查找变成O(logn). 以上就是我对倍增lca的理解. 以洛谷P3128为例, [USACO15DEC]最大流Max Flow 题目描述 Farmer John has installed

POJ 1330 Nearest Common Ancestors LCA

题目链接: http://poj.org/problem?id=1330 题意: 给你一颗有根树,最后输入一对数(a,b),叫你求a和b的公共祖先. 裸的lca,数据也很小,拿来练手不错. 题解: 1.tarjan_lca,离线,线性时间复杂度 代码: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6

LCA-离线tarjan模板

/* *算法引入: *树上两点的最近公共祖先; *对于有根树的两个结点u,v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u,v的祖先且x的深度尽可能大; *对于x来说,从u到v的路径一定经过点x; * *算法思想: *Tarjan_LCA离线算法; *Tarjan算法基于dfs的框架,对于新搜到的一个结点,首先创建由这个结点构成的集合,再对当前结点的每个子树进行搜索; *每搜索完一棵子树,则可确定子树内的LCA询问都已解决,其他的LCA询问的结果必然在这个子树之外; *这时把子树所

ZOJ 3195 Design the city LCA

题目:http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=3195 题意:给定一个树,求三点之间的距离 思路:假定三点为u, v, w,那么(dist[u,v] + dist[v,w] + dist[u,w]) / 2就是答案 总结:wa时不要灰心,也许你离ac不远了 #include<iostream> #include<cstdio> #include<cstring> #include<alg

poj 1330 Nearest Common Ancestors (最简单的LCA)

题意: 给出一棵树的结构. 给出两个点X和Y,求它俩的LCA. 思路: 只需求两个点的LCA,用了两种方法,一种离线tarjan,一种直接搞. 看代码. 代码: 方法一:直接搞. int const maxn = 10005; int T,n,a,b; int fa[maxn]; int X,Y; int main(){ cin>>T; while(T--){ scanf("%d",&n); mem(fa,-1); rep(i,1,n-1){ scanf("