Description
如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌
图(cactus)。所谓简单回路就是指在图上不重复经过任何一个顶点的回路。
举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:、
以及
,而
同时出现在前两个的简单回路里。另外,第三张图也不是仙人图,因为它并不是连通图。显然,仙人图上的每条边,或者是这张仙人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。定义在图上两点之间的距离为这两点之间最短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。现在我们假定仙人图的每条边的权值都是1,你的任务是求出给定的仙人图的直径。
Input
输入的第一行包括两个整数和
以及
。其中
代表顶点个数,我们约定图中的顶
点将从到
编号。接下来一共有
行。代表m条路径。每行的开始有一个整数
,代表在这条路径上
的顶点个数。接下来是个
到
之间的整数,分别对应了一个顶点,相邻的顶点表示存在一条连接这两个顶点的边
。一条路径上可能通过一个顶点好几次,比如对于第一个样例,第一条路径从经过
,又从
返回到了
,但是我们
保证所有的边都会出现在某条路径上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。
Output
只需输出一个数,这个数表示仙人图的直径长度。
Sample Input
15 3 9 1 2 3 4 5 6 7 8 3 7 2 9 10 11 12 13 10 5 2 14 9 15 10 8 10 1 10 1 2 3 4 5 6 7 8 9 10
Sample Output
8 9
HINT
对第一个样例的说明:如图,号点和
号点的最短路径长度为
,所以这张图的直径为
。
Solution
环和链分别考虑。
链直接
环上是由两个点合并过来的,
为
到
在环上的距离。
环上按照顺序,从到
枚举一下,然后对于每一个枚举的
,求最大
对于前面的点,都是同时单调递增,只要维护
最大值。注意队列里要保证最大距离是小于半环的。
为了方便,环拆成两倍,破环成链。
我直接无脑建立圆方树,然后直接算直径,错了。zz
这个数据就不行了。
方点是,那么如果
和
直接算,直接萎了,因为要知道环上距离呀。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<map>
#include<bitset>
#define mk make_pair
#define fi first
#define nd second
#define pii pair<int,int>
#define pb push_back
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;
inline ll read() {ll x = 0; char ch = getchar(), w = 1;while(ch < '0' || ch > '9') {if(ch == '-') w = -1;
ch = getchar();}while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}return x * w;}
void write(ll x) {if(x < 0) putchar('-'), x = -x;if(x > 9) write(x / 10);putchar(x % 10 + '0');}
inline void writeln(ll x) {write(x);puts("");}
const int N = 51000 * 2, M = 510000;
int n, m, tot;
int ans;
struct G2 {
struct Edge {
int u, v, nxt, w;
}e[M * 2];
int head[N], en;
void addedge(int x, int y, int z) {
e[++en].u = x, e[en].v = y, e[en].nxt = head[x], head[x] = en;
e[en].w = z;
}
int f[N], g[N];
void dfs(int x, int F) {
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].v;
if(y == F) continue;
dfs(y, x);
if(f[y] + e[i].w > f[x]) g[x] = f[x], f[x] = f[y] + e[i].w;
else if(f[y] + e[i].w > g[x]) g[x] = f[y] + e[i].w;
}
ans = max(ans, f[x] + g[x]);
}
}g2;
struct G1 {
struct Edge {
int u, v, nxt;
}e[M * 2];
int head[N], en;
void addedge(int x, int y) {
e[++en].u = x, e[en].v = y, e[en].nxt = head[x], head[x] = en;
}
int dfn[N], low[N], num;
int fa[N];
int sum[N];
void solve(int x, int F) {
++tot;
sum[tot] = 1;
int i = x;
while(i != F) {
sum[i] = sum[tot];
++sum[tot];
i = fa[i];
}
i = x;
while(i != F) {
int val = min(sum[i], sum[tot] - sum[i]);
g2.addedge(tot, i, val);
g2.addedge(i, tot, val);
i = fa[i];
}
g2.addedge(tot, F, 0);
g2.addedge(F, tot, 0);
}
void tarjan(int x, int F) {
dfn[x] = low[x] = ++num;
for(int i = head[x]; i;i = e[i].nxt) {
int y = e[i].v;
if(y == F) continue;
if(!dfn[y]) {
fa[y] = x;
tarjan(y, x);
low[x] = min(low[x], low[y]);
} else low[x] = min(low[x], dfn[y]);
if(low[y] <= dfn[x]) continue;
g2.addedge(x, y, 1);
g2.addedge(y, x, 1);
}
for(int i = head[x]; i;i = e[i].nxt) {
int y = e[i].v;
if(fa[y] == x || low[y] != dfn[x]) continue;
solve(y, x);
}
}
}g1;
int main() {
n = read(), m = read(),tot = n;
for(int i = 1; i <= m; ++i) {
int k = read();
int pre;
for(int j = 1; j<= k; ++j) {
int x = read();
if(j > 1) g1.addedge(pre, x), g1.addedge(x, pre);
pre = x;
}
}
g1.tarjan(1, 0);
g2.dfs(1, 0);
writeln(ans);
return 0;
} std
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<map>
#include<bitset>
#define mk make_pair
#define fi first
#define nd second
#define pii pair<int,int>
#define pb push_back
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;
inline ll read() {ll x = 0; char ch = getchar(), w = 1;while(ch < '0' || ch > '9') {if(ch == '-') w = -1;
ch = getchar();}while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}return x * w;}
void write(ll x) {if(x < 0) putchar('-'), x = -x;if(x > 9) write(x / 10);putchar(x % 10 + '0');}
inline void writeln(ll x) {write(x);puts("");}
const int N = 51000 * 2, M = 510000;
int n, m;
int ans;
int f[N];
struct G1 {
struct Edge {
int u, v, nxt;
}e[M * 2];
int head[N], en;
void addedge(int x, int y) {
e[++en].u = x, e[en].v = y, e[en].nxt = head[x], head[x] = en;
}
int dfn[N], low[N], num;
int fa[N], tot, a[N*2];
int q[N*2], h, t;
void solve(int x, int F) {
tot = 0;
for(int i = x; i != fa[F]; i = fa[i]) a[++tot] = i;
for(int i = 1; i <= tot; ++i) a[i + tot] = a[i];
q[h = t = 1] = 1;
f[0] = -1e9;
for(int i = 2; i <= tot * 2; ++i) {
while(h <= t && i - q[h] > tot / 2) ++h;
ans = max(ans, f[a[i]] + f[a[q[h]]] + i - q[h]);
while(h <= t && f[a[i]] >= f[a[q[t]]] + i - q[t]) --t;
q[++t] = i;
}
for(int i = 1; i <= tot; ++i) f[F] = max(f[F], f[a[i]] + min(tot - i, i));
ans = max(ans, f[F]);
}
void tarjan(int x, int F) {
dfn[x] = low[x] = ++num;
for(int i = head[x]; i;i = e[i].nxt) {
int y = e[i].v;
if(y == F) continue;
if(!dfn[y]) {
fa[y] = x;
tarjan(y, x);
low[x] = min(low[x], low[y]);
} else low[x] = min(low[x], dfn[y]);
if(low[y] <= dfn[x]) continue;
ans = max(ans, f[x] + f[y] + 1);
f[x] = max(f[x], f[y] + 1);
ans = max(ans, f[x]);
}
for(int i = head[x]; i;i = e[i].nxt) {
int y = e[i].v;
if(fa[y] == x || low[y] != dfn[x]) continue;
solve(y, x);
}
}
}g1;
int main() {
n = read(), m = read();
for(int i = 1; i <= m; ++i) {
int k = read();
int pre;
for(int j = 1; j<= k; ++j) {
int x = read();
if(j > 1) g1.addedge(pre, x), g1.addedge(x, pre);
pre = x;
}
}
g1.tarjan(1, 0);
writeln(ans);
return 0;
} 
京公网安备 11010502036488号