UVA 11354 Bond

这题就是建立有根树有点问题,其他的都是模板就可以了。。。再就是查询,先调整高度到起始点一样,如果不是同祖先就同时往上找,然后就没别的了。。。
#include <iostream>
#include <stdlib.h>
#include <cstdio>
#include <memory.h>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#define maxn 50005
#define maxm 100005
typedef long long LL;
using namespace std;
struct Edge{
    int from,to,value;
    bool operator < (const Edge &thm)const{
        return value<thm.value;
    }
}road[maxm];
vector<Edge>edges;
vector<int>G[maxn];
bool done[maxn];
int Q,parent[maxn],father[maxn],cost[maxn],dis[maxn];
int m,n;

void init()
{
    edges.clear();
    for(int i=0;i<=n;i++)G[i].clear(),parent[i]=-1,done[i]=0;
    G[50004].clear();
}
void AddEdge(int from,int to,int value)
{
    edges.push_back((Edge){from,to,value});
    int m=edges.size();
    G[from].push_back(m-1);
}
int find(int x)
{
    int s;
    for(s=x;parent[s]>=0;s=parent[s]);
    while(s!=x){
        int tmp=parent[x];
        parent[x]=s;
        x=tmp;
    }
    return s;
}
void Union(int R1,int R2)
{
    int r1=find(R1),r2=find(R2);
    parent[r1]=parent[r1]+parent[r2];
    parent[r2]=r1;
}
void kruskal()
{
    int u,v,num=0;
    for(int i=0;i<m;i++)
    {
        u=road[i].from,v=road[i].to;
        if(find(u)!=find(v))
        {
            AddEdge(u,v,road[i].value);
            AddEdge(v,u,road[i].value);
            Union(u,v);
            num++;
        }
        if(num>=n-1)break;
    }
}
void pre()
{
    memset(father,-1,sizeof father);
    memset(dis,0,sizeof dis);
    memset(done,0,sizeof done);done[1]=1;
    queue<int>Q;
    Q.push(1);
    while(!Q.empty())
    {
        int point=Q.front();Q.pop();
        int number=G[point].size();
        for(int i=0;i<number;i++)
        {
            Edge e = edges[G[point][i]];
            if(!done[e.to])
            {
                done[e.to]=1;
                father[e.to]=e.from;
                cost[e.to]=e.value;
                dis[e.to]=dis[point]+1;
                Q.push(e.to);
            }
        }
    }
}
void solve(int x,int y)
{
    int maxx = -1,maxy = -1;    //初始化两个点到根节点的路的最大边权
    if(dis[x] > dis[y])  //如果x的层数大于y的,即x在y下面
    {
        while(dis[x] > dis[y])
        {
            maxx = max(maxx,cost[x]);   //更新这条路的最大边权
            x = father[x];
        }
    }
    else if(dis[y] > dis[x])
    {
        while(dis[y] > dis[x])
        {
            maxy = max(maxy,cost[y]);   //更新这条路的最大边权
            y = father[y];
        }
    }
    //此时x,y层数相同,然后就可以两边同时向上遍历,更快
    while(x != y)   //当x,y的祖先相同时,就结束算法
    {
        maxx = max(maxx,cost[x]);   //两个节点同时往上走
        x = father[x];
        maxy = max(maxy,cost[y]);
        y = father[y];
    }
    printf("%d\n",max(maxx,maxy));
}
int main()
{
    int count=0;
//    freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        if(count)printf("\n");
        else count++;
        for(int i=0;i<m;i++)scanf("%d%d%d",&road[i].from,&road[i].to,&road[i].value);
        sort(road,road+m);
        init();
        kruskal();
        pre();
        int s,t;
        scanf("%d",&Q);
        while(Q--)
        {
            scanf("%d%d",&s,&t);
            solve(s,t);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值