首页 > 其他 > 详细

【LCA】SPOJ QTREE2

时间:2015-08-03 20:54:31      阅读:238      评论:0      收藏:0      [点我收藏+]

You are given a tree (an undirected acyclic connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. Each edge has an integer value assigned to it, representing its length.

We will ask you to perfrom some instructions of the following form:

  • DIST a b : ask for the distance between node a and node b
    or
  • KTH a b k : ask for the k-th node on the path from node a to node b

Example:
N = 6 
1 2 1 // edge connects node 1 and node 2 has cost 1 
2 4 1 
2 5 2 
1 3 1 
3 6 2 

Path from node 4 to node 6 is 4 -> 2 -> 1 -> 3 -> 6 
DIST 4 6 : answer is 5 (1 + 1 + 1 + 2 = 5) 
KTH 4 6 4 : answer is 3 (the 4-th node on the path from node 4 to node 6 is 3) 

Input

The first line of input contains an integer t, the number of test cases (t <= 25). t test cases follow.

For each test case:

  • In the first line there is an integer N (N <= 10000)
  • In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between ab of cost c (c <= 100000)
  • The next lines contain instructions "DIST a b" or "KTH a b k"
  • The end of each test case is signified by the string "DONE".

There is one blank line between successive tests.

Output

For each "DIST" or "KTH" operation, write one integer representing its result.

Print one blank line after each test.

Example

Input:
1

6
1 2 1
2 4 1
2 5 2
1 3 1
3 6 2
DIST 4 6
KTH 4 6 4
DONE

Output:
5
3


  LCA, 开disRt[u]数组表示节点u到根的距离,用倍增法求节点uv的LCA(w), 则dis(u, v) = (disRt[u] - disRt[w]) + (disRt[v] -
disRt[w]). u至v路径上第k个节点则讨论其实u的祖先还是v的祖先, 再二分查找即可.

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <memory.h>
#include <ctime>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <utility>
#include <stack>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <climits>
using namespace std;

#define clr(_arr) (memset(_arr, 0, sizeof(_arr)))

typedef long long ll;

const int INF = INT_MAX,
          N_MAX  = 10010,
          LG_N_MAX = 20;

int N, LG_N,
    a, b, c,
    root = 1,
    par[LG_N_MAX][N_MAX],//par[m][u] indicates the (2 ^ m)th ancestor of u
    dep[N_MAX], disRt[N_MAX];

char instr[8];

vector<int> G[N_MAX];

typedef pair<int, int> pii;

map<pii, int> len;

void init()
{
    clr(par);
    clr(dep);
    clr(disRt);

    for (int i = 1; i <= N; ++i)
        G[i].clear();

    len.clear();

    LG_N = 0;
    int _N = 1;

    while (_N <= N)
    {
        _N <<= 1;
        ++LG_N;
    }
    ++LG_N;
}

void addEdge(int a, int b, int c)
{
    G[a].push_back(b);
    G[b].push_back(a);

    len[make_pair(a, b)] = c;
    len[make_pair(b, a)] = c;
}

void dfs(int u, int p, int d, int dR)
{
    par[0][u] = p;
    dep[u] = d;
    disRt[u] = dR;

    int out = G[u].size();
    for (int i = 0; i < out; ++i)
    {
        int s = G[u][i];

        if (s != p)
            dfs(s, u, d + 1, dR + len[pii(u, s)]);
    }
}

void pre()
{
    dfs(root, -1, 0, 0);

    //par[m + 1][u] can be obtained only after all par[m][v](v = 1..N) is obtained, and thus the outer loop should be of u
    for (int u = 1; u <= N; ++u)
        for (int m = 0; m + 1 <= LG_N; ++m)
        {
            if (par[m][u] < 0)
                par[m + 1][u] = -1;
            else
                par[m + 1][u] = par[m][par[m][u]];
        }
}

int kthAnt(int u, int k)
{
    for (int m = 0; k; ++m, k >>= 1)
    {
        if (k & 1)
        u = par[m][u];
    }

    return u;
}

int LCA(int u, int v)
{
    if (dep[u] < dep[v])
        swap(u, v);

    u = kthAnt(u, dep[u] - dep[v]);

    if (u == v)
        return u;

    //binary search, search all ancestors of u and v for the last different node index pair, whose parent is LCA(u, v)
    for (int m = LG_N; m >= 0; --m)
        if (par[m][u] != par[m][v])
        {
            u = par[m][u];
            v = par[m][v];
        }

    return par[0][u];
}

int Kth(int u, int v, int k)
{
    int w = LCA(u, v);

    int uw = dep[u] - dep[w] + 1,
        wv = dep[v] - dep[w] + 1,
        _k = k;

    k = (_k <= uw) ? k : (wv - (k - uw));
    u = (_k <= uw) ? u : v;

    return kthAnt(u, k - 1);
}

int main()
{
    int t;

    scanf("%d", &t);

    while(t--)
    {
        bool done = false;

        scanf("%d", &N);

        init();

        for (int i = 1; i < N; ++i)
        {
            scanf("%d %d %d", &a, &b, &c);

            addEdge(a, b, c);
        }

        pre();

        getchar();
        while(!done)
        {
            scanf("%s", instr);

            switch (instr[1])
            {
                case I:
                {
                    scanf("%d %d\n", &a, &b);

                    int w = LCA(a, b);

                    int dis = disRt[a] + disRt[b] - 2 * disRt[w];

                    printf("%d\n", dis);

                    break;
                }
                case T:
                {
                    int k;
                    scanf("%d %d %d\n", &a, &b, &k);

                    printf("%d\n", Kth(a, b, k));

                    break;
                }
                case O:
                {
                    done = true;

                    break;
                }
            }
        }
        printf("\n");
    }

    return 0;
}

 

 

【LCA】SPOJ QTREE2

原文:http://www.cnblogs.com/YangXuanyue/p/4700200.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!