Address
Solution
第一次做仙人掌图。- 主要难在环中 DP 值的处理。
注意题目中提到的性质:
仙人图上的每条边,或者是这张仙人图的桥,或者在且仅在一个简单回路里,两者必居其一。
所以当然先写个 啦 。
- 也是在 ,考虑 的转移。
- 记 表示以点 为起点的最长链长度, 为答案。
- 若
,则
不在一个边双内:
- 对于每个边双,我们找到边双中深度最小的点记为 ,边双中第 个点为 ,共有 个点。
- 则 。
- 同时在边双中任选两个点取最长链也能更新 ,即 。
- 那么对于每个 ,找到 最大的 来更新显然最优,可以用单调队列优化成 ,因此总的时间复杂度 。
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
inline int get()
{
char ch; int res = 0; bool flag = false;
while (ch = getchar(), !isdigit(ch) && ch != '-');
(ch == '-' ? flag = true : res = ch ^ 48);
while (ch = getchar(), isdigit(ch))
res = res * 10 + ch - 48;
return flag ? -res : res;
}
const int N = 1e5 + 5, M = 1e7 + 5, L = 2e5 + 5;
int dfn[N], low[N], dep[N], fa[N], f[N], g[L], h[L];
int n, m, q, ans, tis;
struct Edge
{
int to; Edge *nxt;
}p[M], *lst[N], *P = p;
inline void Link(int x, int y)
{
(++P)->nxt = lst[x]; lst[x] = P; P->to = y;
(++P)->nxt = lst[y]; lst[y] = P; P->to = x;
}
inline void CkMin(int &x, int y) {if (x > y) x = y;}
inline void CkMax(int &x, int y) {if (x < y) x = y;}
inline int Min(int x, int y) {return x < y ? x : y;}
inline void solveDP(int rt, int x)
{
q = dep[x] - dep[rt] + 1;
for (int y = x; y != rt; y = fa[y], --q)
g[q] = f[y];
g[q] = f[rt];
q = dep[x] - dep[rt] + 1;
for (int i = 1; i <= q; ++i)
g[i + q] = g[i];
int tmp = q >> 1, t = 1, w = 0;
for (int i = 1, im = q << 1; i <= im; ++i)
{
while (t <= w && i - h[t] > tmp) ++t;
if (t <= w)
CkMax(ans, g[i] + g[h[t]] + i - h[t]);
while (t <= w && g[i] - i >= g[h[w]] - h[w]) --w;
h[++w] = i;
}
for (int i = 2; i <= q; ++i)
CkMax(f[rt], g[i] + Min(i - 1, q - i + 1));
}
inline void Tarjan(int x)
{
dfn[x] = low[x] = ++tis;
for (Edge *e = lst[x]; e; e = e->nxt)
{
int y = e->to;
if (y == fa[x]) continue;
if (!dfn[y])
{
fa[y] = x;
dep[y] = dep[x] + 1;
Tarjan(y);
CkMin(low[x], low[y]);
}
else CkMin(low[x], dfn[y]);
if (dfn[x] < low[y])
{
CkMax(ans, f[x] + f[y] + 1);
CkMax(f[x], f[y] + 1);
}
}
for (Edge *e = lst[x]; e; e = e->nxt)
{
int y = e->to;
if (fa[y] != x && dfn[x] < dfn[y])
solveDP(x, y);
}
}
int main()
{
n = get(); m = get(); int k, x, y;
while (m--)
{
k = get(); x = get();
while (--k)
{
y = get();
Link(x, y);
x = y;
}
}
Tarjan(1);
printf("%d\n", ans);
}