您的位置:首页 > 其它

How far away ? HDU - 2586 tarjan求LCA

2017-10-03 00:55 369 查看
题意:给你n个村庄,n-1条路将所有村庄联通,每条路都有自己的长度。m次提问,问a,b村庄之间路的长度。

分析:这个就是在一棵树上求两个点的距离嘛。LCA。因为数据范围比较小,暴力的话,每组时间复杂度为m*q,可以卡过去。

用Tarjan的话,每组时间复杂度为m+q,用Tarjan求LCA是一种离线做法,先把所有询问都存起来,然后相同起点的可以一起算。

d[i]:从根到i点的距离

f[i]:i的祖先

vis[i]:标记数组

edge[i]:存边

q[i]:存询问

col[i]:标记目前哪些点可以直接查找

主要的是并查集的使用~妙呀~

(PE是什么鬼,OUTPUT中说每组样例结束后空一行嘛,空了PE。。。不空A了。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <set>
#include <map>

using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn = 4e4+10;
struct node
{
int to,pre,id,v;
}edge[maxn*2];
node q[maxn];
int f[maxn],head[maxn],hq[maxn],vis[maxn],col[maxn];
ll ans[maxn],d[maxn];
void init(int n)
{
mem(edge,0);mem(vis,0);mem(head,-1);mem(hq,-1);mem(q,0);mem(col,0);mem(d,0);
for(int i=1;i<=n;i++)
f[i]=i;
}
int h=0;
void addedge(int from,int to,int v,int id)
{
edge[h].to=to;edge[h].v=v;edge[h].id=id;edge[h].pre=head[from];
head[from]=h;
}
void addq(int from,int to,int v,int id)
{
q[h].to=to;q[h].v=v;q[h].id=id;q[h].pre=hq[from];
hq[from]=h;
}
void dfs(int u,int val)
{
d[u]=val;
for(int i=head[u];i>-1;i=edge[i].pre)
{
int v=edge[i].to;
if(!vis[v])
{
vis[v]=1;
dfs(v,val+edge[i].v);
}
}
}
int getf(int k)
{
if(k==f[k]) return k;
else return f[k]=getf(f[k]);
}
void uin(int a,int b)
{
int x=getf(a),y=getf(b);
if(x!=y) f[y]=x;
}
void Tarjan(int u)
{
for(int i=head[u];i>-1;i=edge[i].pre)
{
node e=edge[i];
if(!vis[e.to])
{
vis[e.to]=1;
Tarjan(e.to);
uin(u,e.to);
}
}
col[u]=1;
for(int i=hq[u];i>-1;i=q[i].pre)
{
node e=q[i];
if(!col[e.to]) continue;
ans[e.id]=d[u]+d[e.to]-2*d[f[getf(e.to)]];//不能直接f[e.to],因为这里确保是最上面的祖先,因为uin的时候f[y]=x,但是以y为爸爸的孩子们的爸爸还没有改到x~
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
h=0;
scanf("%d %d",&n,&m);
init(n);
for(int i=0;i<n-1;i++)
{
int a,b,k;
scanf("%d %d %d",&a,&b,&k);
addedge(a,b,k,i);h++;addedge(b,a,k,i);h++;
}
vis[1]=1;
dfs(1,0);h=0;
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d %d",&a,&b);
addq(a,b,0,i);h++;addq(b,a,0,i);h++;
}
memset(vis,0,sizeof(vis));vis[1]=1;
Tarjan(1);
for(int i=1;i<=m;i++)
{
printf("%I64d\n",ans[i]);
}
//  printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: