hdu 2874Connections between cities LCA

题目链接

给n个城市, m条边, q个询问, 每个询问, 输出城市a和b的最短距离, 如果不联通, 输出not connected。

用并查集判联通, 如果不连通, 那么两个联通块之间加一条权值很大的边。 然后树链剖分.....

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <queue>
#include <stack>
#include <bitset>
using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int mod = 1e9+7;
const int inf = 1061109567;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
const int maxn = 10005;
int head[maxn*2], fa[maxn], son[maxn], sz[maxn], deep[maxn], top[maxn], w[maxn], f[maxn], cnt, num;
ll sum[maxn<<2];
struct node
{
    int to, nextt, w;
}e[maxn*2];
struct ed
{
    int u, v;
    ll w;
    ed(){}
    ed(int u, int v, ll w):u(u),v(v),w(w){}
}edge[maxn];
void init() {
    mem1(head);
    num = cnt = 0;
}
void add(int u, int v, int w) {
    e[num].to = v, e[num].nextt = head[u], e[num].w = w, head[u] = num++;
}
void dfs1(int u, int fa) {
    sz[u] = 1;
    deep[u] = deep[fa]+1;
    son[u] = -1;
    f[u] = fa;
    for(int i = head[u]; ~i; i = e[i].nextt) {
        int v = e[i].to;
        if(v == fa)
            continue;
        dfs1(v, u);
        sz[u] += sz[v];
        if(son[u]==-1||sz[v]>sz[son[u]])
            son[u] = v;
    }
}
void dfs2(int u, int tp) {
    w[u] = ++cnt, top[u] = tp;
    if(~son[u])
        dfs2(son[u], tp);
    for(int i = head[u]; ~i; i = e[i].nextt) {
        int v = e[i].to;
        if(v == f[u]||v == son[u])
            continue;
        dfs2(v, v);
    }
}
void pushUp(int rt) {
    sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void update(int p, ll val, int l, int r, int rt) {
    if(l == r) {
        sum[rt] = val;
        return ;
    }
    int m = l+r>>1;
    if(p<=m)
        update(p, val, lson);
    else
        update(p, val, rson);
    pushUp(rt);
}
ll query(int L, int R, int l, int r, int rt) {
    if(L<=l&&R>=r) {
        return sum[rt];
    }
    int m = l+r>>1;
    ll ret = 0;
    if(L<=m)
        ret += query(L, R, lson);
    if(R>m)
        ret += query(L, R, rson);
    return ret;
}
ll find(int u, int v) {
    int f1 = top[u], f2 = top[v];
    ll ret = 0;
    while(f1 != f2) {
        if(deep[f1]<deep[f2]) {
            swap(f1, f2);
            swap(u, v);
        }
        ret += query(w[f1], w[u], 1, cnt, 1);
        u = f[f1];
        f1 = top[u];
    }
    if(u == v)
        return ret;
    if(deep[u]>deep[v])
        swap(u, v);
    ret += query(w[son[u]], w[v], 1, cnt, 1);
    return ret;
}
int findd(int u) {
    return fa[u] == u?u:findd(fa[u]);
}
int main()
{
    int n, m, q, x, y, z;
    while(cin>>n>>m>>q) {
        init();
        int ecnt = 0;
        for(int i = 1; i<=n; i++)
            fa[i] = i;
        for(int i = 0; i<m; i++) {
            scanf("%d%d%d", &x, &y, &z);
            add(x, y, z);
            add(y, x, z);
            edge[ecnt++] = ed(x, y, z);
            x = findd(x);
            y = findd(y);
            if(x!=y)
                fa[x] = y;
        }
        x = findd(1);
        for(int i = 2; i<=n; i++) {
            y = findd(i);
            if(y!=x) {
                fa[y] = x;
                edge[ecnt++] = ed(x, y, (ll)1e12);
                add(x, y, inf);
                add(y, x, inf);
            }
        }
        dfs1(1, 0);
        dfs2(1, 1);
        for(int i = 0; i<ecnt; i++) {
            if(deep[edge[i].u]>deep[edge[i].v]) {
                swap(edge[i].u, edge[i].v);
            }
            update(w[edge[i].v], edge[i].w, 1, cnt, 1);
        }
        while(q--) {
            scanf("%d%d", &x, &y);
            ll ans = find(x, y);
            if(ans>=1e12) {
                puts("Not connected");
            } else {
                printf("%d\n", ans);
            }
        }
    }

    return 0;
}

 

转载于:https://www.cnblogs.com/yohaha/p/5094600.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值