求救,关于树上倍增
  • 板块学术版
  • 楼主Acfboy
  • 当前回复1
  • 已保存回复1
  • 发布时间2020/7/2 21:41
  • 上次更新2023/11/6 23:45:13
查看原帖
求救,关于树上倍增
40318
Acfboy楼主2020/7/2 21:41

Acfboy702, MAYDAY.

一道题。

输入一个森林,求两点最短路,不存在路径则输出"No connected"

多组数据,每组输入点数,边数和问题数。

做法:树上倍增求LCA,在用根到两点的距离减去两倍LCA到根的距离。前面用并查集处理是否在同一树上。

我好奔溃啊!!

Code:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int  fa[100005], vet[100005], nxt[100005], lo[100005], road[100005], head[100005], 
          f[100005][20], dis[100005];
int  n, m, c, Case, x, y, d, num; 
void add(int u, int v, int d){
    num++;
    vet[num] = v;
    nxt[num] = head[u];
    head[u] = num;
    lo[num] = d;
}
int  findfa(int x){
	if(fa[x] != x) fa[x] = findfa(fa[x]);
	return fa[x];
}
void make(int fat, int u, int deep){
    dis[u] = deep;
    for(int now = head[u];  now; now = nxt[now]){
        int v = vet[now];
        if(v == fat) continue;
        road[v] = road[u] + lo[now];
        make(u, v, deep+1);
    }
}
void makeb(int fat, int u, int j){
    f[u][1] = fat;
    if(dis[u] >= 1<<j) f[u][j] = f[f[f[u][j-1]][1]][j-1];
    for(int now = head[u];  now; now = nxt[now]){
        int  v = vet[now];
        if(v == fat) continue;
        makeb(u, v, j);
    }
}
int  LCA(int u, int v){
    if (dis[u] < dis[v]) swap(u, v); 
    int  maxjump = 0;
    while (1 << (maxjump + 1) <= dis[u]) ++maxjump;
    maxjump += 1;
    for (int j = maxjump; j >= 1; j--) 
        if (dis[u] - (1 << j) + 1 >= dis[v]) 
            u = f[u][j];
    if (u == v) return u; 
    for (int j = maxjump; j >= 1; j--) {
        if (f[u][j] != f[v][j]) {
            u = f[u][j];
            v = f[v][j];
        }
    }
    return f[u][1]; 
}
int main(){
    scanf("%d", &Case);
    while(Case--){
        scanf("%d%d%d", &n, &m, &c);
        for(int i = 1; i <= n; i++)
            fa[i] = i;
        for(int i = 1; i <= m; i++){
            scanf("%d%d%d", &x, &y, &d);
            add(x, y, d);
            add(y, x, d);
            int  fx = findfa(x), fy = findfa(y);
            if(fx != fy) fa[fy] = fx;
        }
        for(int i = 1; i <= n; i++)
            if(fa[i] == i){
                make(0, i, 1);
                for(int j = 2; j <= 20; j++)
                    makeb(0, i, j);
            }
        for(int i = 1; i <= c; i++){
            scanf("%d%d", &x, &y);
            int  fx = findfa(x), fy = findfa(y);
            if(fx != fy){
                printf("Not connected\n");
                continue;
            }
            int  lc = LCA(x, y);
            int  ans = road[x] + road[y] - 2*road[lc];
            printf("%d\n", ans);
        }
        memset(fa, 0, sizeof(fa));
        memset(road, 0, sizeof(road));
        memset(dis, 0, sizeof(dis));
        memset(nxt, 0, sizeof(nxt));
        memset(head, 0, sizeof(head));
        memset(lo, 0, sizeof(lo));
        memset(f, 0, sizeof(fa));
        memset(vet, 0, sizeof(vet));
        num = 0;
    }
    return 0;
}
2020/7/2 21:41
加载中...