IOI 2008 島嶼(基環外向樹)

2021-08-20 09:54:17 字數 3850 閱讀 9661

【ioi 2008】島嶼

給定乙個基環樹森林,求它們的直徑之和。

基環外向樹的直徑分兩類:

1.在某一棵外向樹內部(某個外向樹的直徑)。

2.乙個端點在一棵外向樹內,橫跨環上的一段區間,另乙個端點在另一顆外向樹內。

首先,我們找到基環,然後對於每乙個外向樹都求出能到子樹中可以延伸的最長的距離pa

thi pat

hi

,順便求出外向樹的直徑,更新答案。

接著只需要考慮第二類情況了。任取乙個節點po

int poi

nt

,記環上第

i i

個節點離po

int' role="presentation" style="position: relative;">poi

ntpo

int的距離為di

sti dis

ti

,基環上邊的總距離為su

m sum

,那麼答案為: ma

x max

變形後可以得到: ma

x max

注意:(d

isti

+pat

hi) (di

sti+

path

i)

是可以事先算出來的。

於是通過一些簡單的技巧我們就可以通過此題了。

/*

這邊使用了錯誤的動態規劃,得分36pts

#include #include typedef long long ll;

using namespace std;

const int maxn = 1000005;

const int maxm = 2000005;

bool vis[maxn], mrk[maxn];

int n, road[maxn][2];

int edge, ter[maxn], len[maxn], nxt[maxn], lnk[maxn];

int circle, head, tail, id[maxm], par[maxn], node[maxm];

ll ans, res, sum[maxm], path[maxn], val[maxm];

void addedge(int u, int v, int w)

void tree_diameter(int u)

tree_diameter(v);

res = max(res, path[u] + path[v] + w);

path[u] = max(path[u], path[v] + w);

}}void find_circle(int u)

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

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

break;

}vis[v] = 1;

par[v] = u;

}}ll solve(int u)

head = tail = 0;

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

return res;

}int main()

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

}printf("%lld\n", ans);

return 0;}*/

/*這邊使用了暴力,得分72pts

#include #include typedef long long ll;

using namespace std;

const int maxn = 1000005;

const int maxm = 2000005;

bool vis[maxn], mrk[maxn];

int n, road[maxn][2];

int edge, ter[maxn], len[maxn], nxt[maxn], lnk[maxn];

int circle, head, tail, id[maxm], par[maxn], node[maxm];

ll ans, res, sum[maxm], path[maxn], val[maxm];

void push(int nid, int nval)

id[tail] = nid;

val[tail++] = nval;

}void pop(int pid)

}ll query()

void addedge(int u, int v, int w)

void tree_diameter(int u)

tree_diameter(v);

res = max(res, path[u] + path[v] + w);

path[u] = max(path[u], path[v] + w);

}}void find_circle(int u)

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

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

break;

}vis[v] = 1;

par[v] = u;

}}ll solve(int u)

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

}return res;

}int main()

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

}printf("%lld\n", ans);

return 0;}*/

//下面就是正解了,得分100pts

#include

#include

typedef

long

long ll;

using

namespace

std;

const

int maxn = 1000005;

bool vis[maxn], mrk[maxn];

int n, road[maxn][2];

int edge, ter[maxn], len[maxn], nxt[maxn], lnk[maxn];

int circle, par[maxn], node[maxn];

ll mn, mx, ans, res, sum[maxn], path[maxn];

inline

int read()

while (isdigit(ch))

return ret;

}inline

void addedge(int u, int v, int w)

void find_circle(int u)

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

break;

}vis[v] = 1;

par[v] = u;

}}void tree_diameter(int u)

tree_diameter(v);

res = max(res, path[u] + path[v] + w);

path[u] = max(path[u], path[v] + w);

}}ll solve(int u)

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

return res;

}int main()

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

}printf("%lld\n", ans);

return

0;}

bzoj 1040 騎士 基環外向樹dp

給出n個點n條邊和每個點的點權,一條邊的兩個斷點不能同時選擇,問最大可以選多少。圖是一張基環外向樹森林 是不是很像舞會啊 就是多了一條邊。所以我們考慮一下對於一棵基環外向樹,拆掉一條在環上的邊,變成一棵樹。在這個樹上以斷邊的乙個斷點為根,跑舞會,就得到了這棵樹的最大值 根選和根不選了兩種 考慮到對於...

ACWING 358 島嶼(基環樹直徑)

題意 你準備遊覽乙個公園,該公園由 n 個島嶼組成,當地管理部門從每個島嶼出發向另外乙個島嶼建了一座橋,不過橋是可以雙向行走的。同時,每對島嶼之間都有一艘專用的往來兩島之間的渡船。相對於乘船而言,你更喜歡步行。你希望所經過的橋的總長度盡可能的長,但受到以下的限制 可以自行挑選乙個島開始遊覽。任何乙個...

ZJOI2008 騎士 基環樹

題意見鏈結。本題較為經典,值得一做。基環外向樹練手好題。如果不考慮環的情況,則就是普通樹形dp,f i 0 1 表示這個點取或不取。對於此題一棵樹只能出現乙個環,我們任意刪去環上的一條邊,即可轉環為樹。對於 u,v 1 u 不取,則以 u 為根dp。2 v 不取,則以 v 為根dp。不需要考慮兩個點...