BZOJ 2177 [曼哈顿最小生成树]
2017-03-17 19:32
316 查看
Description
平面坐标系xOy内,给定n个顶点V=(x,y)。对于顶点u,v,u与v之间的距离d定义为|xu–xv|+|yu–yv| 。你的任务就是求出这n个顶点的最小生成树。Solution
把平面划分为八个区域以后只有这八个区域的最近点与该点的连边在Kruscal中有贡献。找到这八个点只要用树状数组维护一下即可。
好像很妙的方法。
有一个地方要去重,不然会WA
#include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int N = 101010; const int INF = 2147483647; inline char get(void) { static char buf[100000], *S = buf, *T = buf; if (S == T) { T = (S = buf) + fread(buf, 1, 100000, stdin); if (S == T) return EOF; } return *S++; } inline void read(int &x) { static char c; x = 0; int sgn = 0; for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1; for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0'; if (sgn) x = -x; } struct Point { int x, y, id; Point (int _x = 0, int _y = 0, int i = 0):x(_x), y(_y), id(i) {} inline friend bool operator <(const Point &a, const Point &b) { return a.x == b.x ? a.y < b.y : a.x < b.x; } inline void Ref(int dir) { if (dir & 1) swap(x, y); else if (dir == 2) x = -x; } }; struct node { int pos, key; node (int p = 0, int k = 0):pos(p), key(k) {} }; struct edge { int from, to, key; edge(int f = 0, int t = 0, int k = 0):from(f), to(t), key(k) {} inline friend bool operator <(const edge &a, const edge &b) { return a.key < b.key; } }; node C ; Point P ; edge G[N << 3]; int n, pos, Gcnt, cnt; long long ans; int mp , v ; int fa , rk ; inline int lowbit(int x) { return x & -x; } inline void Modify(int x, int key, int pos) { for (; x; x -= lowbit(x)) if (C[x].key > key) C[x] = node(pos, key); } inline int Query(int x) { int key = INF, pos = -1; for (; x <= n; x += lowbit(x)) if (C[x].key < key) { key = C[x].key; pos = C[x].pos; } return pos; } inline int Abs(int x) { return x < 0 ? -x : x; } inline int Dis(const Point &a, const Point &b) { return Abs(a.x - b.x) + Abs(a.y - b.y); } inline int F(int x) { return fa[x] == x ? x : fa[x] = F(fa[x]); } inline bool Merge(int x, int y) { static int f1, f2; f1 = F(x); f2 = F(y); if (f1 == f2) return false; if (rk[f1] > rk[f2]) swap(f1, f2); if (rk[f1] == rk[f2]) rk[f2]++; fa[f1] = f2; return true; } inline bool cmp(const int a, const int b) { return v[a] < v[b]; } inline void AddEdge(int from, int to, int key) { G[++Gcnt] = edge(from, to, key); } int main(void) { freopen("1.in", "r", stdin); freopen("1.out", "w", stdout); read(n); for (int i = 1; i <= n; i++) { read(P[i].x); read(P[i].y); P[i].id = i; fa[i] = i; } for (int dir = 0; dir < 4; dir++) { for (int i = 1; i <= n; i++) P[i].Ref(dir); sort(P + 1, P + n + 1); for (int i = 1; i <= n; i++) { mp[i] = i; v[i] = P[i].y - P[i].x; C[i] = node(-1, INF); } sort(mp + 1, mp + n + 1, cmp); cnt = 0; mp[n + 1] = INF; for (int i = 1; i <= n; i++) { ++cnt; while (v[mp[i]] == v[mp[i + 1]]) v[mp[i++]] = cnt; v[mp[i]] = cnt; } // 离散去重 for (int i = n; i; i--) { pos = Query(v[i]); if (~pos) AddEdge(P[i].id, P[pos].id, Dis(P[i], P[pos])); Modify(v[i], P[i].x + P[i].y, i); } } sort(G + 1, G + Gcnt + 1); for (int i = 1; i <= Gcnt; i++) { if (Merge(G[i].from, G[i].to)) { n--; ans += G[i].key; if (n == 1) break; } } cout << ans << endl; }
相关文章推荐
- 【BZOJ-2177】曼哈顿最小生成树 Kruskal + 树状数组
- BZOJ 2177 最小曼哈顿生成树
- [BZOJ2177][最小/最大(曼哈顿距离)生成树]曼哈顿最小生成树
- BZOJ 2177: 曼哈顿最小生成树 曼哈顿最小生成树
- bzoj2177/51nod-1213 曼哈顿距离最小生成树
- BZOJ.2177.曼哈顿最小生成树(Kruskal)
- 曼哈顿距离最小生成树与莫队算法 (BZOJ2038)
- 【BZOJ】1821: [JSOI2010]Group 部落划分 Group(最小生成树+贪心)
- bzoj 1016 最小生成树计数
- 曼哈顿距离最小生成树
- POJ 3241 Object Clustering 曼哈顿距离求最小生成树的第K小边
- POJ 3241 Object Clustering (曼哈顿距离最小生成树)
- bzoj 1601 最小生成树
- BZOJ2561 最小生成树
- BZOJ 2001([Hnoi2010]City 城市建设-CDQ重构图-动态最小生成树)
- bzoj1016: [JSOI2008]最小生成树计数 MST+DFS
- bzoj1601 最小生成树经典建模
- BZOJ 1016 [JSOI2008]最小生成树计数 dfs
- bzoj 2753 最小生成树变形
- BZOJ 2001([Hnoi2010]City 城市建设-CDQ重构图-动态最小生成树)