[SHOI2008]cactus仙人掌图 (tarjan + dp)

来源:互联网 发布:艾欧尼亚30级账号淘宝 编辑:程序博客网 时间:2024/05/20 21:44
Description如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus)。所谓简单回路就是指在图上不重复经过任何一个顶点的回路。  举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:(4,3,2,1,6,5,4)、(7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),而(2,3)同时出现在前两个的简单回路里。另外,第三张图也不是仙人图,因为它并不是连通图。 显然,仙人图上的每条边,或者是这张仙人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。定义在图上两点之间的距离为这两点之间最短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。现在我们假定仙人图的每条边的权值都是1,你的任务是求出给定的仙人图的直径。

早就开始做了。。。最近 czm 提起才想到。。。我觉得这是一道很好的题目。。。

首先求点双连通分量,然后对于每一个环 dp,可能的答案为 max{dis[i] + dis'[j], dis[x] + dist(x, y) + dis[y]}, dis 表示搜索树向下的最长路,dis‘表示第二长路(临时变量记之即可),dist(x, y) 表示仙人掌环上两点间的最短距离。

dp 就单(Ou)调(Shao)队列水过了。。。tarjan 什么的也就水过了。。。

然后爆栈什么的调了我一两个小时。。。最后删掉 dfs 中 3 个临时变量才过。。。

bzoj rank 10,貌似不是很颓。。。

Code :

#include <cstdio>#include <cstdlib>#include <cstring>#include <map>#include <set>#include <queue>#include <algorithm>using namespace std;#define FOR(i, j, k) for (i = (j); i <= (k); ++ i)#define ROF(i, j, k) for (i = (j); i >= (k); -- i)#define FER(i, j, k) for (i = j[k]; i; i = i->n)#define maxn 50005struct da{int t; da * n;};da das[maxn * 4], * adj = das + 1, * edge[maxn];int n, m, dfnn, tot, ans, i, j, k;int dfn[maxn], low[maxn], dis[maxn];da * sta[maxn * 2], ** top = sta;int a[maxn * 2], q[maxn * 2], h, t;void up(int & i, int j) {if (j > i) i = j;}void down(int & i, int j) {if (j < i) i = j;}void solve(int k){int i; q[h = t = 1] = 1;FOR (i, 2, tot){while (i - q[h] > k) ++ h;up(ans, dis[a[q[h]]] - q[h] + dis[a[i]] + i);while (h <= t && dis[a[i]] - i > dis[a[q[t]]] - q[t]) -- t;q[++ t] = i;}}void dfs(int u, int fa){da * e; int l = 0;dfn[u] = low[u] = ++ dfnn;FER (e, edge, u) if (e->t != fa)if (dfn[e->t]) down(low[u], dfn[e->t]);else{* (++ top) = e, dfs(e->t, u), down(low[u], low[e->t]);if (low[e->t] > dfn[u]){-- top;if (dis[e->t] + 1 > dis[u])l = dis[u], dis[u] = dis[e->t] + 1;else if (dis[e->t] + 1 > l)l = dis[e->t] + 1;}else if (low[e->t] == dfn[u]){tot = j = 0;do a[++ tot] = (* top)->t; while (* (top --) != e);FOR (i, 1, tot){up(j, dis[a[i]] + min(i, tot + 1 - i));a[i + tot + 1] = a[i];}a[++ tot] = u, k = tot >> 1, tot = (tot << 1) - 1;solve(k);if (j > dis[u]) l = dis[u], dis[u] = j;else if (j > l) l = j;}}up(ans, l + dis[u]);}void link(int i, int j){* (++ adj) = (da) {j, edge[i]}, edge[i] = adj;* (++ adj) = (da) {i, edge[j]}, edge[j] = adj;}int main(){freopen("cactus.in", "r", stdin);freopen("cactus.out", "w", stdout);int u, v;scanf("%d%d", & n, & m);FOR (i, 1, m){scanf("%d%d", & k, & u);FOR (j, 2, k) scanf("%d", & v), link(u, v), u = v;}dfs(1, 0);printf("%d\n", ans);return 0;}
原创粉丝点击