【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。不需要考慮兩個點...