How far away ? HDU

来源:互联网 发布:创建oracle11g数据库 编辑:程序博客网 时间:2024/05/01 10:23

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 house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.
Input

First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k (1到40000).The houses are labeled from 1 to n.

Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
Output

For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3

2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100

一道LCA的题,第一次接触,网上查了查,根据原理(我参考的是这篇文章,只有方法,没有代码的http://www.cnblogs.com/ECJTUACM-873284962/p/6613379.html),按照自己的理解,写了代码,到现在了,应该要有提供思路,便有写代码的能力(也就是说现在的阶段应该提升思维,拓展思路最为重要),所以我所写的应该还有待优化的地方。这个代码是其中一种实现LCA的方式,有离线的思想
代码

#include<cstdio>#include<iostream>#include<map>#include<cstring>#include<vector>#define maxn 6006using namespace std;struct node{    int a,b;}query[203];//离线保留询问int ans[203];//询问对应的答案struct edge{    int to;    int dis;};//保留边bool vis[203];int n,m;int pre[40004];bool vis2[40004];int dis[40004];vector<edge>tree[40004];void getDis(int x,int father)//求出所有点到根节点的距离{    int v;    for(int i=0;i<tree[x].size();i++)    {        v=tree[x][i].to;        if(v==father)            continue;        dis[v]=dis[x]+tree[x][i].dis;        getDis(v,x);    }}int findd(int x)//使用并查集,但是个人理解和并查集没有太大关系,只是借用了并差集的实现方式{    return pre[x]==x?x:pre[x]=findd(pre[x]);}void LCA(int x,int father)//LCA啦{    int v;    for(int i=0;i<tree[x].size();i++)    {        v=tree[x][i].to;        if(v==father)            continue;        LCA(v,x);    }    for(int i=0;i<m;i++)//对于200的询问量,线性扫一遍即可    {        if(vis[i])            continue;        if(x==query[i].a&&vis2[query[i].b])        {            ans[i]=dis[x]+dis[query[i].b]-2*dis[findd(query[i].b)];            vis[i]=true;        }        else        {            if(x==query[i].b&&vis2[query[i].a])            {                ans[i]=dis[x]+dis[query[i].a]-2*dis[findd(query[i].a)];                vis[i]=true;            }        }    }    int xx=findd(x);    pre[xx]=father;    vis2[x]=true;}int main(){    dis[1]=0;//根到自己的距离当然为0    int t;    int a,b,w;    scanf("%d",&t);    while(t--)    {        memset(vis,false,sizeof(vis));        memset(vis2,false,sizeof(vis2));        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)            tree[i].clear();        for(int i=1;i<=n;i++)            pre[i]=i;//都是初始化,其实我很少写init()函数,因为不知道为什么总是忘了写到main里。。。        for(int i=1;i<n;i++)        {           scanf("%d%d%d",&a,&b,&w);           edge e;           e.dis=w;           e.to=a;           tree[b].push_back(e);//存边           e.to=b;           tree[a].push_back(e);        }        for(int i=0;i<m;i++)        {            scanf("%d%d",&a,&b);            query[i].a=a;            query[i].b=b;//村存查询        }        getDis(1,-1);        //cout<<"yes";        LCA(1,-1);        for(int i=0;i<m;i++)            printf("%d\n",ans[i]);    }    return 0;}

入门LCA的一道好题,难度不大

原创粉丝点击