hdu2874 LCA

题意:现在有 n 个点与 m 条边的无向无环图,但是图不一定完全连通,边有各自的边权,给出多组询问,查询两点之间的路径权值和,或者输出两点不连通。

一开始有最短路的想法,但是由于询问有 1e6 组,做单源最短路肯定会爆炸,而 1e4 的边数又觉得 floyd 时间空间都会炸,又因为是无环图,所以就想到了LCA的做法,大量询问让我很自然地就想到了离线Tarjan。由于不连通,就分多次Tarjan,通过标记来实现是否在同一棵树中。离线Tarjan 搞了一发结果就原来的做法估计是因为vector中的pair需要存问题编号或者是vector本身的原因,总之一直 MLE ,看了 discuss 有人提供了一种问题的存储方法,就是将所有问题也像链式前向星的方法存储,而节点编号分别是 0/1,2/3,这样的,只要用 节点编号/2 就能确定是哪个问题的结果。这样A掉了。但是不能忍的是我看见别人的题解里写的做法是直接递归向上爬LCA的做法……而且不是倍增!是一步一步爬的!递归!而且我交了一发还比离线快!这什么数据啊!卡空间不卡时间!暴力都能过!还更快!我不服!

 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 const int maxn=1e4+1;
 5 const int maxm=2e4+1;
 6 const int maxq=1e6+1;
 7 
 8 int n;
 9 int head[maxn],nxt[maxm],point[maxm],val[maxm],size;
10 int fa[maxn],dis[maxn];
11 int vis1[maxn];
12 int ans[maxq];
13 int head1[maxn],point1[maxq<<1],nxt1[maxq<<1],size1;
14 int cnt;
15 
16 void init(){
17     memset(head,-1,sizeof(head));
18     size=0;
19     memset(head1,-1,sizeof(head1));
20     size1=0;
21     memset(vis1,0,sizeof(vis1));
22     for(int i=1;i<=n;++i)fa[i]=i;
23     memset(ans,-1,sizeof(ans));
24     cnt=0;
25 }
26 
27 void add(int a,int b,int v){
28     point[size]=b;
29     val[size]=v;
30     nxt[size]=head[a];
31     head[a]=size++;
32     point[size]=a;
33     val[size]=v;
34     nxt[size]=head[b];
35     head[b]=size++;
36 }
37 
38 int find(int x){
39     return x==fa[x]?x:fa[x]=find(fa[x]);
40 }
41 
42 void Tarjan(int s,int pre){
43     for(int i=head[s];~i;i=nxt[i]){
44         int j=point[i];
45         if(j!=pre){
46             dis[j]=dis[s]+val[i];
47             Tarjan(j,s);
48             int x=find(j),y=find(s);
49             if(x!=y)fa[x]=y;
50         }
51     }
52     vis1[s]=cnt;
53     for(int i=head1[s];~i;i=nxt1[i]){
54         int j=point1[i];
55         if(vis1[j]==vis1[s]){
56             int lca=find(j);
57             int id=i/2;
58             ans[id]=dis[s]+dis[j]-2*dis[lca];
59         }
60     }
61 }
62 
63 int main(){
64     int m,k;
65     while(scanf("%d%d%d",&n,&m,&k)!=EOF){
66         init();
67         while(m--){
68             int a,b,v;
69             scanf("%d%d%d",&a,&b,&v);
70             add(a,b,v);
71         }
72         for(int i=0;i<k;++i){
73             int a,b;
74             scanf("%d%d",&a,&b);
75             point1[size1]=b;
76             nxt1[size1]=head1[a];
77             head1[a]=size1++;
78             point1[size1]=a;
79             nxt1[size1]=head1[b];
80             head1[b]=size1++;
81         }
82         for(int i=1;i<=n;++i){
83             if(!vis1[i]){
84                 ++cnt;
85                 dis[i]=0;
86                 Tarjan(i,0);
87             }
88         }
89         for(int i=0;i<k;++i){
90             if(ans[i]==-1)printf("Not connected
");
91             else printf("%d
",ans[i]);
92         }
93     }
94     return 0;
95 }
View Code
原文地址:https://www.cnblogs.com/cenariusxz/p/4829694.html