模板倍增LCA 求树上两点距离

http://acm.hdu.edu.cn/showproblem.php?pid=2586

课上给的ppt里的模板是错的,wa了一下午orz。最近总是被坑啊。。。

题解:书上两点距离转化为到根的距离之和减去重复部分,类似前缀和

dis[x] + dis[y] - 2ll * dis[LCA(x, y)]
#define _CRT_SECURE_NO_WARNINGS
#include<cmath>
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<stack>
#include<vector>
#include<string.h>
using namespace std;
#define rep(i,t,n)  for(int i =(t);i<=(n);++i)
#define per(i,n,t)  for(int i =(n);i>=(t);--i)
#define mmm(a,b) memset(a,b,sizeof(a))
#define eps 1e-6
#define pb push_back

typedef long long ll;


stack <int> dl;
const int maxn=1e5+5;
int f[maxn][16];
int fa[maxn];
ll dis[maxn];
int dep[maxn];

int n, m;
 vector<pair<int,ll> > E[maxn];
 void dfs(int rt,int p) {
     
     for (int i = 0; i < E[rt].size(); i++) {
         pair<int,int> v = E[rt][i];
         if (v.first == p)continue;
         fa[v.first] =rt ;
         dep[v.first] =dep[rt]+1 ;
         dis[v.first] = dis[rt] + v.second;
         dfs(v.first, rt);
     }
 }

void Init_LCA() {
    for (int j = 0; (1 << j) <= n; ++j)
        for (int i = 1; i <= n; ++i)
            f[i][j] = -1;
    for (int i = 1; i <= n; ++i) f[i][0] = fa[i];
    for (int j = 1; (1 << j) <= n; ++j)
        for (int i = 1; i <= n; ++i)
            if (f[i][j - 1] != -1)
                f[i][j] = f[f[i][j - 1]][j - 1];
}
int LCA(int x, int y) {
    if (dep[x] < dep[y]) swap(x, y);
    int i, lg;
    for (lg = 0; (1 << lg) <= dep[x]; ++lg);
    --lg;
    /// 使x往上走直到和y在同一水平线上;
    for (i = lg; i >= 0; --i)
        if (dep[x] - (1 << i) >= dep[y])
            x = f[x][i];
    if (x == y) return x;
    /// 此时x,y在同一水平线上,使x,y同时以相同的速度(2^j)往上走;
    for (i = lg; i >= 0; --i)
        if (f[x][i] != -1 && f[x][i] != f[y][i])
            x = f[x][i], y = f[y][i];
    return fa[x];
}
int main()
{
    int t;
    cin >> t;
    while (t--) {
        
        cin >> n >> m;
        rep(i, 1, n)E[i].clear();
        //mmm(dis, 0); mmm(fa, 0); mmm(f, 0); mmm(dep, 0);
        rep(i, 1, n-1) {
            int x, y;
            ll z;
            scanf("%d%d%lld", &x, &y, &z);
            //f[x][0] = y;
            E[x].push_back(make_pair(y,z));
            E[y].push_back(make_pair(x,z));
        }
        dis[1] = 0;
        //fa[1] = 1;
        //dep[1] = 0;
        dfs(1, -1);
        Init_LCA();
        rep(i, 1, m) {
            int x, y;
            scanf("%d%d", &x, &y);
            printf("%lld\n", dis[x] + dis[y] - 2ll * dis[LCA(x, y)]);
            
        }
        //cout << endl;
    }
    cin >> n;
    return 0;
}/*
 2
5 2
1 2 10
2 3 10
3 4 10
4  5 10
1 5
5 3

 
 */

猜你喜欢

转载自www.cnblogs.com/SuuT/p/9362022.html