# 曼哈顿距离最小生成树与莫队算法

|AB|=x1+y1，|AC|=x2+y2，|BC|=|x1-x2|+|y1-y2|。而由于B和C都在y轴向右45度的区域内，有y-x>0且x>0。下面我们分情况讨论：

1.      x1>x2且y1>y2。这与|AB|≤|AC|矛盾；

2.      x1≤x2且y1>y2。此时|BC|=x2-x1+y1-y2，|AC|-|BC|=x2+y2-x2+x1-y1+y2=x1-y1+2*y2。由前面各种关系可得y1>y2>x2>x1。假设|AC|<|BC|即y1>2*y2+x1，那么|AB|=x1+y1>2*x1+2*y2，|AC|=x2+y2<2*y2<|AB|与前提矛盾，故|AC|≥|BC|；

3.      x1>x2且y1≤y2。与2同理；

4.      x1≤x2且y1≤y2。此时显然有|AB|+|BC|=|AC|，即有|AC|>|BC|。

POJ3241 Object Clustering 求曼哈顿距离最小生成树上第k大的边

//POJ3241; Object Clustering; Manhattan Distance MST
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define N 100000
#define INFI 123456789

struct point
{
int x, y, n;
bool operator < (const point &p) const
{ return x == p.x ? y < p.y : x < p.x; }
}p[N + 1];
struct inedge
{
int a, b, w;
bool operator < (const inedge &x) const
{ return w < x.w; }
}e[N << 3 | 1];
struct BITnode
{
int w, p;
}arr[N + 1];
int n, k, tot = 0, f[N + 1], a[N + 1], *l[N + 1], ans;

template <typename T>
inline T abs(T x)
{ return x < (T)0 ? -x : x; }

int find(int x)
{ return x == f[x] ? x : f[x] = find(f[x]); }

inline bool cmp(int *a, int *b)
{ return *a < *b; }

inline int query(int x)
{
int r = INFI, p = -1;
for (; x <= n; x += x & -x)
if (arr[x].w < r) r = arr[x].w, p = arr[x].p;
return p;
}

inline void modify(int x, int w, int p)
{
for (; x > 0; x -= x & -x)
if (arr[x].w > w) arr[x].w = w, arr[x].p = p;
}

inline void addedge(int a, int b, int w)
{
++tot;
e[tot].a = a, e[tot].b = b, e[tot].w = w;
//	printf("%d %d %d\n", a, b, w);
}

inline int dist(point &a, point &b)
{ return abs(a.x - b.x) + abs(a.y - b.y); }

int main()
{
//Initialize
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i)
{
scanf("%d%d", &p[i].x, &p[i].y);
p[i].n = i;
}
//Solve
for (int dir = 1; dir <= 4; ++dir)
{
//Coordinate transform - reflect by y=x and reflect by x=0
if (dir == 2 || dir == 4)
for (int i = 1; i <= n; ++i) p[i].x ^= p[i].y ^= p[i].x ^= p[i].y;
else if (dir == 3)
for (int i = 1; i <= n; ++i) p[i].x = -p[i].x;
//Sort points according to x-coordinate
std::sort(p + 1, p + n + 1);
//Discretize
for (int i = 1; i <= n; ++i) a[i] = p[i].y - p[i].x, l[i] = &a[i];
std::sort(l + 1, l + n + 1, cmp);
/*
int cnt = 1;
for (int i = 2; i <= n; ++i)
if (*l[i] != *l[i - 1]) *l[i - 1] = cnt++;
else *l[i - 1] = cnt;
*l[n] = cnt;
*/
for (int i = 1; i <= n; ++i) *l[i] = i;
//Initialize BIT
for (int i = 1; i <= n; ++i) arr[i].w = INFI, arr[i].p = -1;
//Find points and add edges
for (int i = n; i > 0; --i)
{
int pos = query(a[i]);
if (pos != -1)
addedge(p[i].n, p[pos].n, dist(p[i], p[pos]));
modify(a[i], p[i].x + p[i].y, i);
}
}
//Kruskal
std::sort(e + 1, e + tot + 1);
for (int i = 1; i <= n; ++i) f[i] = i;
for (int i = 1, ec = n; ec > k && i <= tot; ++i)
if (find(e[i].a) != find(e[i].b))
{
f[find(e[i].a)] = find(e[i].b);
if (--ec == k) ans = e[i].w;
}
printf("%d\n", ans);
return 0;
}


Tsinsen A1206 小Z的袜子（其实这题暴力有60分……）

//Tsinsen A1206; 小Z的袜子; Modui Algorithm
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define N 50000
#define Q 50000
#define INFI 123456789

typedef long long ll;
struct edge
{
int next, node;
}e[Q << 1 | 1];
int head[N + 1], tot = 0;
struct point
{
int x, y, n;
bool operator < (const point &p) const
{ return x == p.x ? y < p.y : x < p.x; }
}qt[Q + 1], p[Q + 1];
struct inedge
{
int a, b, w;
bool operator < (const inedge &x) const
{ return w < x.w; }
}ie[Q << 3 | 1];
int cnt = 0;
struct BITnode
{
int w, p;
}arr[Q + 1];
int n, q, col[N + 1], a[Q + 1], *l[Q + 1], f[N + 1], c[N + 1];
ll cur, ans[Q + 1];
bool v[Q + 1];

template <typename T>
inline T abs(T x)
{ return x < (T)0 ? -x : x; }

inline int dist(const point &a, const point &b)
{ return abs(a.x - b.x) + abs(a.y - b.y); }

inline void addinedge(int a, int b, int w)
{
++cnt;
ie[cnt].a = a, ie[cnt].b = b, ie[cnt].w = w;
}

inline void addedge(int a, int b)
{
head[a] = tot, e[tot].node = b;
}

inline bool cmp(int *a, int *b)
{ return *a < *b; }

inline int query(int x)
{
int r = INFI, p = -1;
for (; x <= q; x += x & -x)
if (arr[x].w < r) r = arr[x].w, p = arr[x].p;
return p;
}

inline void modify(int x, int w, int p)
{
for (; x > 0; x -= x & -x)
if (arr[x].w > w) arr[x].w = w, arr[x].p = p;
}

int find(int x)
{ return x == f[x] ? x : f[x] = find(f[x]); }

inline ll calc(int x)
{ return (ll)x * (x - 1); }

inline void add(int l, int r)
{
for (int i = l; i <= r; ++i)
{
cur -= calc(c[col[i]]);
cur += calc(++c[col[i]]);
}
}

inline void remove(int l, int r)
{
for (int i = l; i <= r; ++i)
{
cur -= calc(c[col[i]]);
cur += calc(--c[col[i]]);
}
}

void dfs(int x, int l, int r)
{
v[x] = true;
//Process right bound
if (r < qt[x].y)
add(r + 1, qt[x].y);
else if (r > qt[x].y)
remove(qt[x].y + 1, r);
//Process left bound
if (l < qt[x].x)
remove(l, qt[x].x - 1);
else if (l > qt[x].x)
add(qt[x].x, l - 1);
ans[x] = cur;
//Moving on to next query
for (int i = head[x]; i; i = e[i].next)
{
if (v[e[i].node]) continue;
dfs(e[i].node, qt[x].x, qt[x].y);
}
//Revert changes
//Process right bound
if (r < qt[x].y)
remove(r + 1, qt[x].y);
else if (r > qt[x].y)
add(qt[x].y + 1, r);
//Process left bound
if (l < qt[x].x)
add(l, qt[x].x - 1);
else if (l > qt[x].x)
remove(qt[x].x, l - 1);
}

ll gcd(ll a, ll b)
{ return !b ? a : gcd(b, a % b); }

int main()
{
//Initialize
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; ++i) scanf("%d", col + i);
for (int i = 1; i <= q; ++i) scanf("%d%d", &qt[i].x, &qt[i].y);

//Manhattan MST
for (int i = 1; i <= q; ++i) p[i] = qt[i], p[i].n = i;
for (int dir = 1; dir <= 4; ++dir)
{
//Coordinate transform
if (dir == 2 || dir == 4)
for (int i = 1; i <= q; ++i) std::swap(p[i].x, p[i].y);
else if (dir == 3)
for (int i = 1; i <= q; ++i) p[i].x = -p[i].x;
//Sort by x-coordinate
std::sort(p + 1, p + q + 1);
//Discretize
for (int i = 1; i <= q; ++i) a[i] = p[i].y - p[i].x, l[i] = &a[i];
std::sort(l + 1, l + q + 1, cmp);
int cnt = 1;
for (int i = 2; i <= q; ++i)
if (*l[i] == *l[i - 1]) *l[i - 1] = cnt;
else *l[i - 1] = cnt++;
*l[q] = cnt;
//Initialize BIT
for (int i = 1; i <= q; ++i) arr[i].w = INFI, arr[i].p = -1;
//Find points and add edges
for (int i = q; i > 0; --i)
{
int pos = query(a[i]);
if (pos != -1)
addinedge(p[i].n, p[pos].n, dist(p[i], p[pos]));
modify(a[i], p[i].x + p[i].y, i);
}
}
//Kruskal
std::sort(ie + 1, ie + cnt + 1);
//Initialize disjoint set
for (int i = 1; i <= q; ++i) f[i] = i;
for (int i = 1; i <= cnt; ++i)
if (find(ie[i].a) != find(ie[i].b))
{
f[find(ie[i].a)] = find(ie[i].b);
}

//Modui Algorithm
++c[col[1]];
dfs(1, 1, 1);

//Output
for (int i = 1; i <= q; ++i)
{
ll x = ans[i], y = calc(qt[i].y - qt[i].x + 1);
if (!x) printf("0/1\n");
else
{
ll g = gcd(x, y);
printf("%I64d/%I64d\n", x / g, y / g);
}
}

return 0;
}