【題解】Kattis – Boxes

【題目敘述】https://open.kattis.com/problems/boxes
【解題想法】最近共同祖先 (LCA), 稀疏表 (Sparse Table), 倍增法

  • vector<int> v[maxn]:adjacency list,存圖(某個盒子內有哪些盒子)
  • p[maxn][20]:紀錄每個節點的 2^i 倍祖先 (2^20 = 1e6 > 200000) ,for LCA
  • siz[maxn]: subtree size of each node (每個盒子及其內含的盒子總數)
  • dep[maxn]: depth of each node,紀錄每個盒子位處第幾層。(虛構的節點-0,假想有一個超大的盒子,所有的盒子都放置其中。)
  • 讀入測資
    • p[i][0]:第i個節點的parent (2^0 倍祖先)
    • v[p[i][0]].push_back(i); 第p[i][0]個盒子裏多了「盒子-i」
  • p[j][i] = p[p[j][i-1]][i-1]; 「節點-j」的 2^i 倍祖先 等於 「節點-j」的 2^(i-1) 倍祖先的 「2^(i-1) 倍祖先」
  • DFS計算每個節點的深度及其子樹的節點數目。
  • LCA查詢某個盒子是否處於其它的盒子內,如果是的話,不重複計算這個盒子及其內含的盒子數目。
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 200000;
int n, Q, p[maxn][20], root, siz[maxn], dep[maxn], tmp, q[20], ans;
bool flag;
vector <int> v[maxn];

int dfs(int node, int d){
    dep[node] = d + 1;
    if (v[node].empty()){
        siz[node] = 1;
        return 1;
    }
    int total = 1;
    for (int i:v[node]){
        total += dfs(i, d+1);
    }
    siz[node] = total;
    return siz[node];
}

int lca(int a, int b){
    if (dep[b] < dep[a]) swap(a, b);
    if (dep[a] != dep[b]){
        int dif = dep[b] - dep[a];
        for (int i = 0; i < 20; i++){
            if (dif & 1) b = p[b][i];
            dif >>= 1;
        }
    }
    if (a == b) return a;
    for (int i = 19; i >= 0; i--){
        if (p[a][i] != p[b][i]){
            a = p[a][i];
            b = p[b][i];
        }
    }
    return p[a][0];
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> p[i][0];
        v[p[i][0]].push_back(i);
    }
    for (int i = 1; i < 20; i++){
        for (int j = 1; j <= n; j++){
            p[j][i] = p[p[j][i-1]][i-1];
        }
    }
    dfs(0, 0);
    cin >> Q;
    while (Q--){
        cin >> tmp;
        ans = 0;
        for (int i = 0; i < tmp; i++){
            cin >> q[i];
        }
        if (tmp == 1) cout << siz[q[0]] << "\n";
        else{
            for (int i = 0; i < tmp; i++){
                flag = true;
                for (int j = 0; j < tmp; j++){
                    if (i == j) continue;
                    if (lca(q[i], q[j]) == q[j]){
                        flag = false;
                        break;
                    }
                }
                if (flag) ans += siz[q[i]];
            }
            cout << ans << "\n";
        }
    }
}
分享本文 Share with friends