HDU 2874 LCA 最近公共祖先

这道题一次RE 。。查询的数组 开小了= =

一次MLE     Vector开大了。。无力吐槽

这题很巧妙在于建立一个虚拟根节点 0,它到所有点的距离都为0,如果两个点的LCA为0,就说明这2个点不相连。

LCA这篇博客讲得很好http://dongxicheng.org/structure/lca-rmq/

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<string>
#define inf 0x7fffffff
#define maxn 10010
#define maxq 1000010
using namespace std;
typedef struct node
{
    int v,w;
}N;
int n,m,k;
vector<N> v1[maxn],v2[maxn];
int vis[maxn];
int color[maxn];
int ans[maxq];
int dis[maxn];
int fa[maxn];
int anc[maxn];
void init()
{
    int i;
    for(i=0;i<=n;i++)
    {
        v1[i].clear();
        v2[i].clear();
        fa[i]=i;
    }
    memset(vis,0,sizeof(vis));
    memset(color,0,sizeof(color));
    memset(ans,-1,sizeof(ans));
    memset(dis,0,sizeof(dis));
    memset(anc,-1,sizeof(anc));
}

int find(int x)
{
    if(fa[x]!=x)
    fa[x]=find(fa[x]);
    return fa[x];
}
void merge(int x,int y)
{
    fa[find(x)]=find(y);
}

void tarjan(int u)
{
    int i;
    vis[u]=1;
    anc[u]=u;
    for(i=0;i<v1[u].size();i++)
    {
        int v=v1[u][i].v;
        if(vis[v]==0)
        {
            dis[v]=dis[u]+v1[u][i].w;
            tarjan(v);
            merge(v,u);
            anc[find(u)]=u;
        }
    }
    color[u]=1;
    for(i=0;i<v2[u].size();i++)
    {
        int vv=v2[u][i].v;
        if(color[vv]==1&&find(vv)!=0)
        {
            int w=v2[u][i].w;
            ans[w]=dis[u]+dis[vv]-2*dis[anc[find(vv)]];
        }
    }
    return ;
}


int main() {
   freopen("in.txt","r",stdin);
   while(scanf("%d%d%d",&n,&m,&k)==3)
   {
       init();
       int i;
       for(i=1;i<=n;i++)
       {
           N nod;
           nod.v=i;
           nod.w=0;
           v1[0].push_back(nod);
           nod.v=0;
           nod.w=0;
           v1[i].push_back(nod);
       }
       int a,b,c;
       for(i=0;i<m;i++)
       {
           scanf("%d%d%d",&a,&b,&c);
           N nod;
           nod.v=b;
           nod.w=c;
           v1[a].push_back(nod);
           nod.v=a;
           nod.w=c;
           v1[b].push_back(nod);
       }
       for(i=0;i<k;i++)
       {
           scanf("%d%d",&a,&b);
           N nod;
           nod.v=b;
           nod.w=i;
           v2[a].push_back(nod);
           nod.v=a;
           nod.w=i;
           v2[b].push_back(nod);
       }
       tarjan(0);
       for(i=0;i<k;i++)
       {
           if(ans[i]==-1)
           printf("Not connected\n");
           else
           printf("%d\n",ans[i]);
       }
   }
   return 0;
}







评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值