BZOJ 1791: [IOI2008]Island 岛屿 - 基环树
题解
题意 = 找出无向基环树森林的每颗基环树的直径。
我们首先需要找到每颗基环树的环, 但是因为是无向图,用tarjan找环, 加个手工栈, 我也是看了dalao的博客才知道tarjan找无向图环 :
然鹅大佬的方法有一点小问题, 无法找出只有两个节点的环,改动后代码:
1 void dfs(int x, int last) { 2 dfn[x] = ++sz; 3 for(int i = head[x]; i; i = e[i].nxt) { 4 if(i == last ^ 1) continue; 5 int nt = e[i].to; 6 if(dfn[nt]) { 7 if(dfn[nt] < dfn[x]) continue; 8 cur.push_back(x); mk[x] = 1; 9 for(; nt != x; nt = pre[nt]) cur.push_back(nt), mk[nt] = 1; 10 } 11 else pre[nt] = x, dfs(nt, i); 12 } 13 }
加了手工栈后的代码
1 int lev2; 2 3 int st_i2[N],st_x2[N],st_y2[N],st_t2[N]; 4 5 #define i st_i2[lev2] 6 #define y st_y2[lev2] 7 #define x st_x2[lev2] 8 #define nt st_t2[lev2] 9 10 void dfs(int u, int last) { 11 lev2 = 1; 12 st_x2[1] = u; st_y2[1] = last; 13 start:; 14 dfn[x] = ++sz; 15 for(i = head[x]; i; i = e[i].nxt) { 16 nt = e[i].to; 17 if(i == ch(y)) continue; 18 if(dfn[nt]) { 19 if(dfn[nt] < dfn[x]) continue; 20 cur.push_back(x); mk[x] = 1; 21 for(; nt != x; nt = pre[nt]) mk[nt] = 1, cur.push_back(nt); 22 continue; 23 } 24 pre[nt] = x; 25 st_x2[lev2 + 1] = nt; 26 st_y2[lev2 + 1] = i; 27 lev2++; 28 goto start; 29 end:; 30 } 31 lev2--; 32 if(lev2) goto end; 33 } 34 35 #undef i 36 #undef y 37 #undef x 38 #undef nt
设tmp 为某棵基环树的直径
tmp可能是某个环上点的子树的直径, 也有可能是环上两个点之间的距离+两个点到子树的最大距离
找出环后, 求出环上的每个点的子树中的直径, 每颗子树的直径中都更新 tmp的最大值。
接着求出从环上每个点到它子树节点的最远距离$d$, tmp的最大值也可能为 $d_i + d_j + dist(i, j)$。
这个式子最大值可以用拆环+单调队列O(N)求出。
然后把tmp 加到最后答案
代码
为什么不加手工栈比加了手工栈慢20倍
1 #include<cstring> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #define rd read() 6 #define rep(i,a,b) for(int i = (a); i <= (b); ++i) 7 #define per(i,a,b) for(int i = (a); i >= (b); --i) 8 #define ll long long 9 #define R register 10 using namespace std; 11 12 const int N = 1e6 + 1e5; 13 14 int n, head[N], tot, dfn[N], pre[N], sz; 15 int q[N], mk[N], pos[N]; 16 ll ans, d[N], f[N]; 17 18 vector<int> pt; 19 vector<ll> len; 20 21 struct edge { 22 int nxt, to, val; 23 }e[N << 2]; 24 25 int read() { 26 R int X = 0, p = 1; R char c = getchar(); 27 for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 28 for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 29 return X * p; 30 } 31 32 void add(int u, int v, int val) { 33 e[++tot].to = v; 34 e[tot].val = val; 35 e[tot].nxt = head[u]; 36 head[u] = tot; 37 } 38 39 int ch(int x) { 40 return ((x + 1) ^ 1) - 1; 41 } 42 43 int lev2; 44 45 int st_i2[N],st_x2[N],st_y2[N],st_t2[N]; 46 47 #define i st_i2[lev2] 48 #define y st_y2[lev2] 49 #define x st_x2[lev2] 50 #define nt st_t2[lev2] 51 52 void dfs(int u, int last) { 53 lev2 = 1; 54 st_x2[1] = u; st_y2[1] = last; 55 start:; 56 dfn[x] = ++sz; 57 for(i = head[x]; i; i = e[i].nxt) { 58 nt = e[i].to; 59 if(i == ch(y)) continue; 60 if(dfn[nt]) { 61 if(dfn[nt] < dfn[x]) continue; 62 pt.push_back(x); mk[x] = 1; 63 for(; nt != x; nt = pre[nt]) mk[nt] = 1, pt.push_back(nt); 64 continue; 65 } 66 pre[nt] = x; 67 st_x2[lev2 + 1] = nt; 68 st_y2[lev2 + 1] = i; 69 lev2++; 70 goto start; 71 end:; 72 } 73 lev2--; 74 if(lev2) goto end; 75 } 76 77 #undef i 78 #undef y 79 #undef x 80 #undef nt 81 82 int lev; 83 int st_x[N], st_y[N], st_i[N], st_t[N]; 84 85 #define i st_i[lev] 86 #define x st_x[lev] 87 #define y st_y[lev] 88 #define nt st_t[lev] 89 90 void dfs2(int u, int fa) { 91 lev = 1; 92 st_x[1] = u; st_y[1] = fa; 93 start:; 94 for(i = head[x]; i; i = e[i].nxt) { 95 nt = e[i].to; 96 if(nt == y || mk[nt]) continue; 97 st_x[lev + 1] = nt; 98 st_y[lev + 1] = x; 99 lev++; 100 goto start; 101 end:; 102 f[x] = max(f[x], f[nt]); 103 f[x] = max(f[x], d[x] + d[nt] + e[i].val); 104 d[x] = max(d[x], d[nt] + e[i].val); 105 } 106 lev--; 107 if(lev) goto end; 108 } 109 110 #undef i 111 #undef x 112 #undef y 113 #undef nt 114 115 void work(int x) { 116 ll tmp = 0; int cnt; 117 pt.clear(); len.clear(); 118 dfs(x, 0); cnt = pt.size(); 119 pt.push_back(pt[0]); 120 len.push_back(0); 121 for(R int i = 0; i < cnt; ++i) { 122 for(R int k = head[pt[i]]; k; k = e[k].nxt) if(e[k].to == pt[(i + 1) % cnt]) 123 len.push_back(e[k].val); 124 } 125 for(R int i = 1; i < cnt; ++i) 126 pt.push_back(pt[i]), len.push_back(len[i]); 127 128 rep(i, 1, cnt * 2 - 1) { 129 len[i] += len[i - 1]; 130 } 131 rep(i, 0, cnt - 1) dfs2(pt[i], 0), tmp = max(tmp, f[pt[i]]); 132 int l = 1, r = 0; 133 rep(i, 0, cnt * 2 - 1) { 134 while(l <= r && i - q[l] >= cnt) l++; 135 if(l <= r) tmp = max(tmp, d[pt[i]] + d[pt[q[l]]] + len[i] - len[q[l]]); 136 else tmp = max(tmp, d[pt[i]]); 137 while(l <= r && d[pt[i]] - len[i] >= d[pt[q[r]]] - len[q[r]]) r--; 138 q[++r] = i; 139 } 140 ans += tmp; 141 } 142 143 int main() 144 { 145 n = rd; 146 rep(i, 1, n) { 147 int v = rd, val = rd; 148 add(i, v, val); add(v, i, val); 149 } 150 rep(i, 1, n) if(!dfn[i]) { 151 work(i); 152 } 153 printf("%lld\n", ans); 154 }