CF 609E, 树链剖分
Posted 茶杯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF 609E, 树链剖分相关的知识,希望对你有一定的参考价值。
题目大意:给你一个联通无向图,问你包含某条边的最小生成树的大小是多少
解:做一个最小生成树,如果询问边在树上,则答案是最小生成树,否则则是这条边+树构成的环上去掉一条最大树边后得到的树。这里用树剖处理即可。
有个sb错误,因为问题是边权,而树剖的链一般是以点为单位,如果采用边权下放到点的技巧的话,注意lca的点权不要计算进来。
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <utility> 5 #include <map> 6 #include <string> 7 #include <cmath> 8 #include <vector> 9 #include <cstring> 10 #include <stack> 11 #include <set> 12 #include <queue> 13 14 using namespace std; 15 16 #define SQR(x) ((x)*(x)) 17 #define LL long long 18 #define LOWBIT(x) ((x)&(-(x))) 19 #define PB push_back 20 #define MP make_pair 21 #define SQR(x) ((x)*(x)) 22 #define LSON(x) ((x)<<1) 23 #define RSON(x) (((x)<<1)+1) 24 25 26 27 #define MAXN 211111 28 29 const double EPS = 1e-6; 30 31 LL ans, spanTree; 32 int n, m; 33 34 struct line{ 35 int a, b, c, id; 36 line(int a = 0, int b = 0, int c = 0, int d = 0): a(a), b(b), c(c), id(d) {} 37 bool operator < (const line &rhs) const { 38 return c < rhs.c; 39 } 40 }; 41 42 line a[MAXN]; 43 int w[MAXN]; 44 45 struct DisjointSet{ 46 int f[MAXN], n; 47 void init(int nn = MAXN - 10) { 48 n = nn; 49 for (int i = 0; i <= n; ++i) { 50 f[i] = i; 51 } 52 } 53 int get(int x) { 54 return f[x] == x ? x : f[x] = get(f[x]); 55 } 56 void joint(int x, int y) { 57 f[x] = y; 58 } 59 } DjS; 60 61 struct data{ 62 int dest, cost; 63 data *nxt; 64 data(int a = 0, int b = 0, data *c = 0): dest(a), cost(b), nxt(c) {} 65 }; 66 67 struct TreeArray{ 68 int tree[MAXN], n; 69 int a[MAXN]; 70 void init(int nn = MAXN - 1) { 71 n = nn; 72 memset(tree, 0, sizeof(tree[0])*(n+10)); 73 } 74 void add(int x, int num = -1) { 75 a[x] = num; 76 while (x <= n) { 77 tree[x] = max(tree[x], num); 78 x += LOWBIT(x); 79 } 80 } 81 int get(int x, int y) { 82 int res = -1; 83 while (x <= y) { 84 if (y - LOWBIT(y) >= x) { 85 res = max(res, tree[y]); 86 y -= LOWBIT(y); 87 } else { 88 res = max(res, a[y]); 89 --y; 90 } 91 } 92 return res; 93 } 94 } TA; 95 96 struct Tree{ 97 data edge[MAXN*2], *vect[MAXN]; 98 int n, cnt; 99 int sz[MAXN], top[MAXN], heavy[MAXN], father[MAXN], dep[MAXN], lab[MAXN], num; 100 int root; 101 //???0?4??0?3??0?3?? 102 void add(int x, int y, int z) { 103 edge[++cnt] = data(y, z, vect[x]); vect[x] = &edge[cnt]; 104 } 105 106 void init(int nn = MAXN - 10, int roott = 1) { 107 n = nn; 108 cnt = num = 0; 109 memset(vect, 0, sizeof(vect[0])*(n+10)); 110 memset(father, -1, sizeof(father[0])*(n+10)); 111 root = roott; 112 } 113 114 void split_dfs1(int u = 1) { 115 sz[u] = 1; heavy[u] = -1; 116 for (data *i = vect[u]; i; i = i->nxt) { 117 if (i->dest == father[u]) continue; 118 father[i->dest] = u; 119 dep[i->dest] = dep[u] + 1; 120 w[i->dest] = i->cost; 121 split_dfs1(i->dest); 122 sz[u] += sz[i->dest]; 123 if (heavy[u] == -1 || sz[i->dest] > sz[heavy[u]]) heavy[u] = i->dest; 124 } 125 } 126 127 void split_dfs2(int u = 1, int anc = 1) { 128 top[u] = anc; lab[u] = ++num; 129 TA.add(lab[u], w[u]); 130 if (heavy[u] != -1) split_dfs2(heavy[u], anc); 131 for (data *i = vect[u]; i; i = i->nxt) { 132 if (i->dest != father[u] && i->dest != heavy[u]) split_dfs2(i->dest, i->dest); 133 } 134 } 135 136 void split() { 137 w[root] = -1; 138 dep[root] = 1; 139 father[root] = -1; 140 141 split_dfs1(root); 142 143 num = 0; 144 145 split_dfs2(root, root); 146 } 147 148 int query(int u, int v) { 149 int res = -1; 150 //cout << "query ================ " << ‘ ‘<< endl; 151 //cout << u << ‘ ‘<< v << endl; 152 //cout << top[u] <<‘ ‘<< top[v] << endl; 153 while (top[u] != top[v]) { 154 if (dep[top[u]] < dep[top[v]]) swap(u, v); 155 //todo 156 // cout << u << ‘ ‘<< v << ‘ ‘<< top[u] << ‘ ‘<< top[v] << endl; 157 res = max(res, TA.get(lab[top[u]], lab[u])); 158 // cout << res << endl; 159 //todo end 160 u = father[top[u]]; 161 } 162 if (dep[u] > dep[v]) swap(u, v); 163 164 //cout << u << ‘ ‘<< v << endl; 165 //cout << lab[u] << ‘ ‘ << lab[v] << endl; 166 //todo 167 res = max(res, TA.get(lab[u]+1, lab[v])); 168 //todo end 169 return res; 170 } 171 } G; 172 173 void init() { 174 cin >> n >> m; 175 DjS.init(n); 176 G.init(n); 177 TA.init(n); 178 179 int x, y, z; 180 for (int i = 0; i < m; ++i) { 181 cin >> x >> y >> z; 182 a[i] = line(x, y, z, i); 183 } 184 sort(a, a + m); 185 int cnt = 0; 186 spanTree = 0; 187 188 for (int i = 0 ; i < m; ++i) { 189 int x = a[i].a, y = a[i].b; 190 x = DjS.get(x); y = DjS.get(y); 191 if (x != y) { 192 //cout << "=============" << endl; 193 //cout << a[i].a << ‘ ‘ << a[i].b << ‘ ‘<< a[i].c << endl; 194 DjS.joint(x, y); 195 spanTree += a[i].c; 196 ++cnt; 197 G.add(a[i].a, a[i].b, a[i].c); 198 G.add(a[i].b, a[i].a, a[i].c); 199 a[i].c *= -1; 200 } 201 if (cnt + 1 == n) break; 202 } 203 204 G.split(); 205 206 } 207 208 bool cmp2(const line &a, const line &b) { 209 return a.id < b.id; 210 } 211 212 void solve() { 213 214 //cout << spanTree << endl; 215 sort(a, a + m, cmp2); 216 ans = 0; 217 for (int i = 0; i < m; ++i) { 218 if (a[i].c < 0) { 219 ans = spanTree; 220 } 221 else { 222 ans = spanTree - G.query(a[i].a, a[i].b) + a[i].c; 223 //cout << a[i].a << ‘ ‘ << a[i].b << endl; 224 //cout << G.query(a[i].a, a[i].b) << ‘ ‘<< a[i].c << endl; 225 } 226 cout << ans << endl; 227 } 228 } 229 230 int main() { 231 //freopen("test.txt", "r", stdin); 232 ios::sync_with_stdio(false); 233 init(); 234 solve(); 235 return 0; 236 }
以上是关于CF 609E, 树链剖分的主要内容,如果未能解决你的问题,请参考以下文章