cychester

BZOJ 1791: [IOI2008]Island 岛屿 - 基环树

传送门

 

题解

题意 = 找出无向基环树森林的每颗基环树的直径。 

我们首先需要找到每颗基环树的环, 但是因为是无向图,用tarjan找环, 加个手工栈, 我也是看了dalao的博客才知道tarjan找无向图环 :

dalao的链接

然鹅大佬的方法有一点小问题, 无法找出只有两个节点的环,改动后代码:

 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 }
View Code

 

posted on 2018-08-30 13:42  cychester  阅读(530)  评论(0编辑  收藏  举报

导航