1. 程式人生 > >求樹上每兩點的距離之和

求樹上每兩點的距離之和

給定一棵n個節點的樹和n-1條邊的權值,求每兩點間的權值的總和。\((n \leq 1e5)\)

  • 暴力做法
    求出每兩個點的\(lca (O(nlogn)\)預處理,\(O(logn)\)查詢),預處理路徑字首和後\(O(1)\)求得
    \(n^2\)數量級的點對,時間複雜度\(O(n^2logn)\),TLE了。

  • 正解:統計每條邊被經過的次數,乘以權值,求和

1.每條邊連線了兩個聯通塊\(a b\),一個有\(k\)個點,一個有\(n-k\)個點。
2.因為要求的是任意兩點的距離和,故每條邊在\(a\)中的每一個點與\(b\)中的每一個點的路徑上出現,即出現了\(k*(n-k)\)

次,再乘以權值即可。
3.做一遍預處理,對每個節點求出子樹大小,即可在\(O(n)\)的時間內求出每兩點的權值總和

主要程式碼:

int siz[maxn];
void dfs(int u, int fa)
{
    siz[u] = 1;
    ou[u] = ou[fa] ^ 1;
    for (auto v:G[u])
    {
        if (v != fa)
        {
            dfs(v, u);
            siz[u] += siz[v];
        }
    }
}

for (int i = 1; i <= n; ++i)
        ans += 1ll * siz[i] * (n - siz[i]) * w[i];