[HDOJ2586]How far away?(最近公共祖先 瞎写)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586

给一个图,找两个点最近公共祖先。

这几天数据取证课上得蛋疼,根本没有时间看什么算法。今晚翘课做大物实验,回来虽然没下课但是也不想去了。于是窝在实验室做一两道题爽一下也是不错的。

膜拜一下tarjan,据说以tarjan命名的算法有三个,好强啊,什么时候我也能像他一样呢(恐怕一辈子都不可能了吧(笑))

插入边的时候统计出入度,以便后来选择谁来做根节点。同时为了查询方便,我用map来存边。这道题解决完输入问题后,开始标记每一个节点在我刚刚标记的图上的层次遍历的深度和它的相应父节点,之后就可以查询最近公共祖先了,注意查询的时候先加边权再更新点。

代码:

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <iomanip>
  4 #include <cstring>
  5 #include <climits>
  6 #include <complex>
  7 #include <fstream>
  8 #include <cassert>
  9 #include <cstdio>
 10 #include <bitset>
 11 #include <vector>
 12 #include <deque>
 13 #include <queue>
 14 #include <stack>
 15 #include <ctime>
 16 #include <set>
 17 #include <map>
 18 #include <cmath>
 19 
 20 using namespace std;
 21 
 22 typedef struct Edge {
 23     int u, v;
 24     int next;
 25 }Edge;
 26 
 27 typedef pair<int, int> pii;
 28 const int maxn = 40010;
 29 int n, m;
 30 int ecnt;
 31 int head[maxn];
 32 int depth[maxn], parent[maxn];
 33 int in[maxn], out[maxn];
 34 int root;
 35 map<pii, int> el;
 36 Edge e[maxn];
 37 
 38 void init() {
 39     ecnt = 0;
 40     el.clear();
 41     memset(head, -1, sizeof(head));
 42     memset(e, 0, sizeof(e));
 43 }
 44 
 45 void adde(int u, int v, int w) {
 46     e[ecnt].u = u;
 47     e[ecnt].v = v;
 48     in[v]++;
 49     out[u]++;
 50     e[ecnt].next = head[u];
 51     head[u] = ecnt++;
 52     el[pii(u, v)] = w;
 53 }
 54 
 55 void dfs(int u, int p, int d) {
 56     parent[u] = p;
 57     depth[u] = d;
 58     for(int i = head[u]; ~i; i = e[i].next) {
 59         if(p != e[i].v) {
 60             dfs(e[i].v, u, d+1);
 61         }
 62     }
 63 }
 64 
 65 int lca(int u, int v) {
 66     int ans = 0;
 67     while(depth[u] > depth[v]) {
 68         ans += el[pii(parent[u], u)];
 69         u = parent[u];
 70     }
 71     while(depth[v] > depth[u]) {
 72         ans += el[pii(parent[v], v)];
 73         v = parent[v];
 74     }
 75     while(u != v) {
 76         ans += el[pii(parent[u], u)];
 77         ans += el[pii(parent[v], v)];
 78         u = parent[u];
 79         v = parent[v];
 80     }
 81     return ans;
 82 }
 83 
 84 int main() {
 85     // freopen("in", "r", stdin);
 86     int T;
 87     int u, v, w;
 88     scanf("%d", &T);
 89     while(T--) {
 90         init();
 91         scanf("%d %d", &n, &m);
 92         for(int i = 0; i < n-1; i++) {
 93             scanf("%d %d %d", &u, &v, &w);
 94             adde(u, v, w);
 95         }
 96         for(int i = 1; i <= n; i++) {
 97             if(in[i] == 0) {
 98                 root = i;
 99                 break;
100             }
101         }
102         dfs(root, -1, 0);
103         while(m--) {
104             scanf("%d %d", &u, &v);
105             printf("%d\n", lca(u, v));
106         }
107     }
108     return 0;
109 }

 

也可以把map换成一个hash,数据太水可以这么搞。

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>

using namespace std;

typedef struct Edge {
    int u, v;
    int next;
}Edge;

typedef pair<int, int> pii;
const int maxn = 40010;
const int mod = 1111111;
int n, m;
int ecnt;
int head[maxn];
int depth[maxn], parent[maxn];
int in[maxn], out[maxn];
int root;
int has[mod];
Edge e[maxn];

#define con(u, v) ((parent[u]*1005)%mod+(u*217)%mod)%mod

void init() {
    ecnt = 0;
    memset(has, 0, sizeof(has));
    memset(head, -1, sizeof(head));
    memset(e, 0, sizeof(e));
}

void adde(int u, int v, int w) {
    e[ecnt].u = u;
    e[ecnt].v = v;
    in[v]++;
    out[u]++;
    e[ecnt].next = head[u];
    head[u] = ecnt++;
    has[((u*1005)%mod+(v*217)%mod)%mod] = w;
}

void dfs(int u, int p, int d) {
    parent[u] = p;
    depth[u] = d;
    for(int i = head[u]; ~i; i = e[i].next) {
        if(p != e[i].v) {
            dfs(e[i].v, u, d+1);
        }
    }
}

int lca(int u, int v) {
    int ans = 0;
    while(depth[u] > depth[v]) {
        ans += has[con(u, u)];
        u = parent[u];
    }
    while(depth[v] > depth[u]) {
        ans += has[con(v, v)];
        v = parent[v];
    }
    while(u != v) {
        ans += has[con(u, u)];
        ans += has[con(v, v)];
        u = parent[u];
        v = parent[v];
    }
    return ans;
}

int main() {
    // freopen("in", "r", stdin);
    int T;
    int u, v, w;
    scanf("%d", &T);
    while(T--) {
        init();
        scanf("%d %d", &n, &m);
        for(int i = 0; i < n-1; i++) {
            scanf("%d %d %d", &u, &v, &w);
            adde(u, v, w);
        }
        for(int i = 1; i <= n; i++) {
            if(in[i] == 0) {
                root = i;
                break;
            }
        }
        dfs(root, -1, 0);
        while(m--) {
            scanf("%d %d", &u, &v);
            printf("%d\n", lca(u, v));
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/kirai/p/5256183.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值