HDU 2586 - How far away?

 

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

 

题意 :

给一颗树和每条边的边权, 查询树上两点路径上的边权之和

 

思路 :

十分裸, 先将查询转化

查询节点x到节点y的路径上的边权和, 等于 x到它们最近公共祖先的边权和 + y到他们公共祖先的边权和  

distance(x, y) = distance(x, LCA(x, y)) + distance(y, LCA(x, y))

这个也等于x到根节点的距离 + y到根节点的距离 - 2 *他们最近公共祖先到根节点距离

distance(x, y) = distance(x, root) + distance(y, root) - 2 * distance(LCA(x, y), root)

所以关键就在于维护每一个节点到根节点的距离和找出两点间的LCA节点

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int MAXN = 4e4+10;

typedef struct Edge{
    int v, w;
    Edge(int v1, int w1) {
        v = v1, w = w1;
    }
} Edge;

vector<Edge> edge[MAXN];
int seq[2*MAXN];
int depth[2*MAXN];
int dp[2*MAXN][25];
int dis[MAXN];
int pos[MAXN];
int cnt;

void Dfs(int u, int fa, int dep)
{
    seq[++cnt] = u;
    pos[u] = cnt;
    depth[cnt] = dep;
    int len = edge[u].size();
    for(int i = 0; i < len; i++) {
        int v = edge[u][i].v;
        if(v != fa) {
            dis[v] = dis[u] + edge[u][i].w;
            Dfs(v, u, dep+1);
            seq[++cnt] = u;
            depth[cnt] = dep;
        }
    }
}

void RMQ_Init(int n)
{
    for(int i = 1; i <= n; i++) {
        dp[i][0] = i;
    }
    for(int j = 1; (1 << j) <= n; j++) {
        for(int i = 1; i + (1 << j) - 1 <= n; i++) {
            int a = dp[i][j-1], b = dp[i + (1 << (j-1))][j-1];
            dp[i][j] = depth[a] < depth[b] ? a : b;
        }
    }
}

int RMQ_Query(int l, int r)
{
    int k = 0;
    while((1 << (k+1)) <= r - l + 1) k++;
    int a = dp[l][k], b = dp[r-(1<<k)+1][k];
    return depth[a] < depth[b] ? a : b;
}

int LCA(int u, int v)
{
    int a = pos[u], b = pos[v];
    if(a > b) {
        swap(a, b);
    }
    int res = RMQ_Query(a, b);
    return seq[res];
}

void Init(int n)
{
    for(int i = 0; i <= n; i++) {
        edge[i].clear();
    }
}

int main()
{
    int t;
    int n, m;
    int u, v, w;

    scanf("%d", &t);
    while(t--) {
        scanf("%d %d", &n, &m);
        Init(n);
        for(int i = 0; i < n-1; i++) {
            scanf("%d %d %d", &u, &v, &w);
            edge[u].push_back(Edge(v, w));
            edge[v].push_back(Edge(u, w));
        }
        cnt = 0;
        dis[1] = 0;
        Dfs(1, -1, 0);
        RMQ_Init(cnt);
        while(m--) {
            scanf("%d %d", &u, &v);
            printf("%d\n", dis[u] + dis[v] - 2 * dis[LCA(u, v)]);
        }
    }

    return 0;
}
View Code

 

posted @ 2015-10-21 16:17  Quinte  阅读(141)  评论(0编辑  收藏  举报