bzoj1023: [SHOI2008]cactus仙人掌图
学习了一下圆方树。
圆方树是一种可以处理仙人掌的数据结构,具体见这里:http://immortalco.blog.uoj.ac/blog/1955
简单来讲它是这么做的:用tarjan找环,然后对每个环建立一个新点,然后将环上的边删去,并环上的每个点都连到新点上。这样我们就可以把一个环缩成一个菊花图,重复这么做,一棵仙人掌就变成一棵树啦!这棵树就叫做圆方树,其中原点叫圆点,新点叫方点。
圆方树和原仙人掌很相似,而且它又是一棵树,于是我们就可以在上面dp啦!不过要注意的是对于方点的处理,不能直接更新,要作一个单调队列,因为环上有两种走法么。
期间调了很久,而且我还不会生成数据,orz cbh。
tarjan求DCC都不会写了,我好弱啊~
#include <bits/stdc++.h> #define N 110000 using namespace std; int n, m, nn; vector <int> V[N], W[N]; int low[N], dfn[N], dfsnum; int f[N]; int ans; int shed[N], top; deque <int> Q; void tarjan(int t, int f) { dfn[t] = low[t] = ++ dfsnum; shed[++ top] = t; for (int p = 0; p < V[t].size(); ++ p) if (V[t][p] != f) if (!dfn[V[t][p]]) { tarjan(V[t][p], t); low[t] = min(low[t], low[V[t][p]]); if (low[V[t][p]] >= dfn[t]) { if (shed[top] != V[t][p]) { nn ++; int cur; do { //W[shed[top]].push_back(nn); W[nn].push_back(cur = shed[top]); shed[top --] = 0; } while (cur != V[t][p]); W[t].push_back(nn); //W[nn].push_back(t); } else { W[t].push_back(shed[top]); //W[shed[top]].push_back(t); shed[top --] = 0; } } } else low[t] = min(low[t], dfn[V[t][p]]); } void dfs(int t) { f[t] = 0; int s = W[t].size(); if (t > n) { for (int p = 0; p < s; ++ p) dfs(W[t][p]); for (int q = 0; q < (s + 1) / 2; ++ q) { while (!Q.empty() && f[W[t][Q.back()]] + Q.back() < f[W[t][q]] + q) Q.pop_back(); Q.push_back(q); } for (int p = 0, q = (s + 1) / 2; p < s; ++ p, q = (q == s? 0: q + 1) ) { if (q != s) { while (!Q.empty() && f[W[t][Q.back()]] + (Q.back() < p? Q.back() + s + 1 - p: Q.back() - p) < f[W[t][q]] + (q < p? q + s + 1 - p: q - p)) Q.pop_back(); Q.push_back(q); } if (Q.front() == p) Q.pop_front(); if (!Q.empty()) ans = max(ans, f[W[t][p]] + f[W[t][Q.front()]] + (Q.front() > p? Q.front() - p: Q.front() + s + 1 - p)); } for (int p = 0; p < (s + 1) / 2; ++ p) f[t] = max(f[t], f[W[t][p]] + p); for (int p = (s + 1) / 2; p < s; ++ p) f[t] = max(f[t], f[W[t][p]] + s - 1 - p); Q.clear(); } else { int mx1 = 0, mx2 = 0; for (int p = 0; p < s; ++ p) { dfs(W[t][p]); if (f[W[t][p]] + 1 > mx1) mx2 = mx1, mx1 = f[W[t][p]] + 1; else if (f[W[t][p]] + 1 > mx2) mx2 = f[W[t][p]] + 1; } ans = max(ans, mx1 + mx2); f[t] = mx1; } } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; ++ i) { int k, a; scanf("%d%d", &k, &a); for (int i = 2; i <= k; ++ i) { int b; scanf("%d", &b); V[a].push_back(b); V[b].push_back(a); a = b; } } nn = n; tarjan(1, 0); //puts("haha"); dfs(1); printf("%d\n", ans); }