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示例...