一道很经典的lca入门题。写完收获颇多。
链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
分析:写这道题首先要懂得一种rmq算法,我用的是st算法,我想线段树应该也可以吧。然后还要知道lca是什么东东(废话了==)。有几个工作要做。 1:建图,我用的指针链表。 2:dfs构造数组。 3:用st算法求值。
4:回收内存(如果用链式前向星就不需要了,我的代码也没回收,结果就是很吃内存)。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 400000+10;
struct edge
{
int to,value;
edge *next;
};
struct tu
{
edge *next;
};
tu dian[N];
int first[N],len[N],du[N>>1],book[N],tail;
int f[N>>1][25];
void Addedge(int a,int b,int v);
int dfs(int t,int dis);
void MakeRmq(int n);
int Anwer(int s,int v);
int main()
{
int t,i,j,n,m,a,b,v;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=1; i<=n; i++)
dian[i].next = NULL;
memset(du,0,sizeof(du));
memset(len,0,sizeof(len));
memset(book,0,sizeof(book));
memset(first,0,sizeof(first));
for(i=1; i<n; i++)
{
scanf("%d%d%d",&a,&b,&v);
Addedge(a,b,v);
Addedge(b,a,v);
}
tail = 0;
dfs(1,0);
MakeRmq(tail);
while(m--)
{
scanf("%d%d",&a,&b);
int ans1 = Anwer(first[a],first[b]);
printf("%d\n",len[a]+len[b]-2*ans1);
}
}
system("pause");
return 0;
}
void Addedge(int a,int b,int v) //建图
{
edge *l = new(edge);
l->to = b;
l->value = v;
l->next = dian[a].next;
dian[a].next = l;
}
int dfs(int t,int dis)
{
if(!book[t])
{
du[++tail] = t;
book[t] = 1;
len[t] = dis;
first[t] = tail;
}
edge *l = dian[t].next;
while(l != NULL)
{
if(!book[l->to])
{
dfs(l->to,dis+l->value);
du[++tail] = t;
}
l = l->next;
}
}
void MakeRmq(int n)
{
int i,j;
for(i=1; i<=n; i++)
{
f[i][0] = len[du[i]];
}
for(j=1; (1<<j) < n; j++)
for(i=1; i+(1<<(j))<=n; i++)
{
f[i][j] = min(f[i][j-1] , f[i+(1<<(j-1))][j-1]);
}
}
int Anwer(int s,int v)
{
if(s > v)
{
int t = s;
s = v;
v = t;
}
int m = log2(v-s+1);
return min(f[s][m],f[v-(1<<m)+1][m]);
}