SPOJ - QTREE2 Query on a tree II樹鏈剖分

SPOJ - QTREE2 Query on a tree II

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 a, b 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

題意:
給一棵樹,維護兩點間距離和路徑上第k的結點的編號。
解:
樹鏈剖分。
在求KTH時,由於遍歷過程根據路徑左右兩端結點所在重鏈深度來回跳,故設置一個flag(flag=0從起點向上拉的鏈,flag=1從終點向上拉的鏈)記錄現在爬的是左邊還是右邊的重鏈。
flag有兩種情況會改變:
(1)交換x, y
(2)循環top[x] != top[y]結束時。因爲此時,假設flag=1,則意味着從終點拉的鏈連到了起點多次跳轉後所在的重鏈上(假設跳轉到同一條重鏈上時,起點在終點下方),則此時是從起點向上跳,flag變爲0。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN = 1000000 + 10;

struct Edge{
    int t, w, id;
    Edge(int a=0, int b=0, int c=0):t(a), w(b), id(c){}
};

int n;
vector<Edge> map[MAXN];

struct rmq{
    int w[MAXN], tree[MAXN << 2];

    void build(int l, int r, int id) {
        if (l == r) {
          tree[id] = w[l];
          return;
        }
        int mid = l + r >> 1;
        build(l, mid, id << 1);
        build(mid + 1, r, (id << 1) + 1);
        tree[id] = tree[id << 1] + tree[(id << 1) + 1];
    }

    int query(int l, int r, int a, int b, int id) {
        if (a <= l && r <= b) return tree[id];
        int mid = l + r >> 1, res = 0;
        if (a <= mid && l <= b) res += query(l, mid, a, b, id << 1);
        if (mid < b && a <= r) res += query(mid+1, r, a, b, (id << 1) + 1);
        return res;
    }
}RMQ;

struct chainDivide{
    int fa[MAXN], dep[MAXN], son[MAXN], size[MAXN], top[MAXN], w[MAXN], tid[MAXN], bid[MAXN];
    int tot;

    void find(int x, int father, int depth) {
        fa[x] = father;
        son[x] = 0;
        size[x] = 1;
        dep[x] = depth;
        int maxsize = 0;
        for (int i = 0; i < map[x].size(); ++i) {
          Edge cur = map[x][i];
          if (cur.t == father) continue;
          find(cur.t, x, depth + 1);
          size[x] += size[cur.t];
          w[cur.t] = cur.w;
          if (maxsize < size[cur.t]) {
            maxsize = size[cur.t];
            son[x] = cur.t;
          }
        }
    }

    void connect(int x, int ancestor) {
        top[x] = ancestor;
        tid[x] = ++tot;
        if (son[x]) {
          connect(son[x], ancestor);
          for (int i = 0; i < map[x].size(); ++i) {
            Edge cur = map[x][i];
            if (tid[cur.t]) continue;
            connect(cur.t, cur.t);
          }
        }
    }

    int query(int x, int y) {
        int res = 0;
        while (top[x] != top[y]) {
          if (dep[top[x]] < dep[top[y]]) swap(x, y);
          res += RMQ.query(1, n, tid[top[x]], tid[x], 1);
          x = fa[top[x]];
        }
        if (dep[x] > dep[y]) swap(x, y);
        res += RMQ.query(1, n, tid[x]+1, tid[y], 1);
        return res; 
    }   

    int query2(int x, int y, int k) {
        vector<int> bri[2];
        int flag = 0;
        while (top[x] != top[y]) {
          if (dep[top[x]] < dep[top[y]]) swap(x, y), flag ^= 1;
          for (int i = tid[x]; i >= tid[top[x]]; --i) bri[flag].push_back(bid[i]);
          x = fa[top[x]];
        }   
        flag ^= 1;  
        if (dep[x] > dep[y]) swap(x, y), flag ^= 1;
        for (int i = tid[y]; i >= tid[x]; --i) bri[flag].push_back(bid[i]);
        if (bri[0].size() >= k) return bri[0][k-1];
        else return bri[1][bri[1].size()+bri[0].size()-k];
    }

    void init() {
        memset(tid, 0, sizeof tid);
        w[1] = tot = 0;
        find(1, 0, 1);
        connect(1, 1);
        for (int i = 1; i <= n; ++i) {
          RMQ.w[tid[i]] = w[i];
          bid[tid[i]] = i;
        }
        RMQ.build(1, n, 1);
    }
}CD;

char s[20];

int main()
{
    freopen("in.txt", "r", stdin);
    int T, a, b, c;
    scanf("%d", &T);
    while (T--) {
      scanf("%d", &n);
      for (int i = 1; i <= n; ++i) map[i].clear();
      for (int i = 1; i < n; ++i) {
        scanf("%d%d%d", &a, &b, &c);
        map[a].push_back(Edge(b, c, i));
        map[b].push_back(Edge(a, c, i));
      }
      CD.init();
      while (scanf("%s", s) && s[1] != 'O') {
        scanf("%d%d", &a, &b);
        if (s[0] == 'D')
          printf("%d\n", CD.query(a, b));
        else {
          scanf("%d", &c);
          printf("%d\n", CD.query2(a, b, c));
        }
      }
    }
    return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章