51Nod 1322 關於樹的函式

2021-07-31 08:21:13 字數 1869 閱讀 5253

acm模版

典型的樹歸問題,複雜度 o(

n2) 。

暫且不說樹歸部分,我們先考慮任何一種狀態下如何求 s(

e1,e

2)2 。其實這裡我們並不需要直接算出 a1、a2、b1、b2,只需要根據部分資料就能推出其他資料。

假如 a1 集合中有 n 個結點,那麼 a2 集合中有 n - n 個結點。假如 b1 集合中有 m 個結點,那麼 b2 集合中有 n-m 個結點。

假如 a1 與 b1 交集有 cnt 個結點,那麼 a1 與 b2 交集有 n-cnt 個結點,那麼 a2 與 b1 交集有 m-cnt 個結點,那麼 a2 與 b2 交集有 n-m-n+cnt 個結點。

假如……那麼……沒了,這個部分就這樣!

接著就是樹歸部分,如何列舉出所有情況?首先我們可以對 tree1 的乙個子樹進行 dfs(),標記為集合 a1,然後在這個狀態下對 tree2 進行 dfs_(),這個部分就切切實實是樹歸了,在回溯的過程中進行上述規則的計數累加即可。

具體的還是要分析**,理解了樹歸也就不難看懂**了。

這裡利用了 tuple 容器,如果不用這個容器就需要用到結構體指標了,畢竟 dfs_() 過程中要返回兩個值,分別是 cnt 和 m。

#include 

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long ll;

typedef tuple tii;

const

int maxn = 4e3 + 10;

int n;

int n; // a1集合結點數

ll res = 0;

vector

tree[maxn];

vector

tree_[maxn];

tii tmp;

struct edge

tr[maxn], tr_[maxn];

int vis[maxn];

tii dfs_(int last, int root)

m++;

int a, b;

for (int i = 0; i < tree_[root].size(); i++)

}if (m == n)

long

long maxres = 0;

maxres = max(maxres, (ll)cnt * cnt);

maxres = max(maxres, (ll)(n - cnt) * (n - cnt));

maxres = max(maxres, (ll)(m - cnt) * (m - cnt));

maxres = max(maxres, (ll)(n - m - n + cnt) * (n - m - n + cnt));

res += maxres;

return make_tuple(cnt, m);

}void dfs(int last, int root)

}}int main(int argc, const

char * argv)

for (int i = 1; i < n; i++)

for (int i = 1; i < n; i++)

cout

<< res << '\n';

return

0;}

51nod 1322 關於樹的函式

給出n個點的兩棵無根樹,編號都是從0到n 1 現在每棵樹任意選出一條邊割斷,設第一棵樹選出的邊為e1,第二棵樹選出的邊為e2 很顯然割斷後兩棵樹各分成了四棵樹,設第一棵樹分成了a1樹和b1樹,第二棵樹分成了a2樹和b2樹 設s a,b 為a樹和b樹之間相同編號的點的個數 那麼割斷這兩條邊的價值為s ...

51nod 1737 樹的重心

思路 樹的重心也叫樹的質心。找到乙個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心,刪去重心後,生成的多棵樹盡可能平衡。考慮每一條邊被統計進答案幾次,若斷開這條邊後樹形成大小為s1 s2的兩個聯通塊則這條邊最多被統計min s1,s2 次。刪去重心後任意同一聯通塊中的兩點不構成路...

51nod 1405 樹的距離之和

給定一棵無根樹,假設它有n個節點,節點編號從1到n,求任意兩點之間的距離 最短路徑 之和。input 第一行包含乙個正整數n n 100000 表示節點個數。後面 n 1 行,每行兩個整數表示樹的邊。output 每行乙個整數,第i i 1,2,n 行表示所有節點到第i個點的距離之和。input示例...