【BZOJ 1023】【SHOI 2008】cactus仙人掌图
http://z55250825.blog.163.com/blog/static/150230809201412793151890/
tarjan的时候如果是树边则做树形DP(遇到环就无视),最后在tarjan回溯前扫一遍当前点为“最高点”的环,进行环上DP,这个环上DP是$O(n^2)$的,但如果我们用单调队列优化则是$O(n)$的
总复杂度$O(n)$真是无限仰膜OTZ
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 500003; void read(int &k) { k = 0; int fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = (k << 1) + (k << 3) + c - '0'; k = k * fh; } struct node {int nxt, to;} E[N << 1]; int ans = 0, point[N], n, m, cnt = 0, l, r; int deep[N], F[N], fa[N], DFN[N], low[N], Q[N << 1], tb[N << 1]; void ins(int x, int y) {E[++cnt] = (node) {point[x], y}; point[x] = cnt;} void __(int rt, int x) { int tot = deep[x] - deep[rt] + 1, num = tot << 1, top = tot >> 1; for(int tmp = x; tmp != rt; tmp = fa[tmp]) tb[tot--] = F[tmp]; tb[1] = F[rt]; tot = deep[x] - deep[rt] + 1; for(int i = 1; i <= tot; ++i) tb[tot + i] = tb[i]; l = r = 1; Q[1] = 1; for(int i = 2; i <= num; ++i) { while (l <= r && i - Q[l] > top) ++l; ans = max(ans, tb[i] + i + tb[Q[l]] - Q[l]); while (l <= r && tb[Q[r]] - Q[r] <= tb[i] - i) --r; Q[++r] = i; } for(int i = 2; i <= tot; ++i) F[rt] = max(F[rt], tb[i] + min(i - 1, tot - i + 1)); } void _(int x) { DFN[x] = low[x] = ++cnt; for(int tmp = point[x]; tmp; tmp = E[tmp].nxt) { int v = E[tmp].to; if (v == fa[x]) continue; if (!DFN[v]) { fa[v] = x; deep[v] = deep[x] + 1; _(v); low[x] = min(low[x], low[v]); } else low[x] = min(low[x], DFN[v]); if (DFN[x] < low[v]) { ans = max(ans, F[x] + F[v] + 1); F[x] = max(F[x], F[v] + 1); } } for(int tmp = point[x]; tmp; tmp = E[tmp].nxt) { int v = E[tmp].to; if (x == fa[v] || DFN[x] > DFN[v]) continue; __(x, v); } } int main() { read(n); read(m); int u, v, k; for(int i = 1; i <= m; ++i) { read(k); read(u); for(--k; k; --k) {read(v); ins(u, v); ins(v, u); u = v;} } cnt = 0; _(1); printf("%d\n", ans); return 0; }
仙人掌虽然偏,但是不知道也不可以,这个代码是我磕了一晚上题解的成果QAQ
NOI 2017 Bless All