1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
Time Limit: 5 Sec Memory Limit: 64 MB Submit: 1102 Solved: 446 [Submit][Status][Discuss]Description
了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l≤Xi,Yi≤[1..10^9];Xi,Yi∈整数.当满足下列两个条件之一,两只奶牛i和j是属于同一个群的:
1.两只奶牛的曼哈顿距离不超过C(1≤C≤10^9),即lXi - xil+IYi - Yil≤C.
2.两只奶牛有共同的邻居.即,存在一只奶牛k,使i与k,j与k均同属一个群.
给出奶牛们的位置,请计算草原上有多少个牛群,以及最大的牛群里有多少奶牛
Input
第1行输入N和C,之后N行每行输入一只奶牛的坐标.
Output
仅一行,先输出牛群数,再输出最大牛群里的牛数,用空格隔开.
Sample Input
4 2 1 1 3 3 2 2 10 10
* Line 1: A single line with a two space-separated integers: the number of cow neighborhoods and the size of the largest cow neighborhood.
* Line 1: A single line with a two space-separated integers: the number of cow neighborhoods and the size of the largest cow neighborhood.
Sample Output
2 3
OUTPUT DETAILS: There are 2 neighborhoods, one formed by the first three cows and the other being the last cow. The largest neighborhood therefore has size 3.
OUTPUT DETAILS: There are 2 neighborhoods, one formed by the first three cows and the other being the last cow. The largest neighborhood therefore has size 3.
先处理曼哈顿距离
把每个点从$(x, y)$变为$(x',y')$,其中$x'=x+y,y'=x-y$,这样两个点$(i,j)$的曼哈顿距离就变为了$max(left|x_i'-x_j'
ight|,left|y_i'-y_j'
ight|)$
处理完之后先按照$x'$排序,再维护一个队列,里面$x'$的大小之差不超过$c$
然后对里面维护以$y'$为关键字的平衡树,查找前驱后继,如果$y'$的差不超过$c$,则用并查集加到同一个集合
#include <set> #include <cstdio> #include <algorithm> using namespace std; char buf[10000000], *ptr = buf - 1; inline int readint(){ int n = 0; char ch = *++ptr; while(ch < '0' || ch > '9') ch = *++ptr; while(ch <= '9' && ch >= '0'){ n = (n << 1) + (n << 3) + ch - '0'; ch = *++ptr; } return n; } const int maxn = 100000 + 10; int N, c, ans; struct Node{ int x, y, id; Node(){} Node(int _x, int _y, int _id): x(_x), y(_y), id(_id){} }a[maxn]; class cmp1{ public: bool operator () (const Node &a, const Node &b){ return a.x < b.x; } }; class cmp2{ public: bool operator () (const Node &a, const Node &b){ if(a.y != b.y) return a.y < b.y; else return a.x < b.x; } }; set<Node, cmp2> s; int fa[maxn], cnt[maxn] = {0}; int Find(int x){ return x == fa[x] ? x : fa[x] = Find(fa[x]); } inline void Union(int x, int y){ x = Find(x); y = Find(y); if(x != y){ fa[x] = y; ans --; } } void solve(){ int now = 1; s.insert(a[1]); set<Node>::iterator it1, it2; for(int i = 2; i <= N; i++){ while(a[i].x - a[now].x > c){ s.erase(s.find(a[now])); now++; } s.insert(a[i]); it1 = it2 = s.find(a[i]); if(it1 != s.begin()){ it1--; if(a[i].y - (*it1).y <= c) Union(a[i].id, (*it1).id); } it2++; if(it2 != s.end()){ if((*it2).y - a[i].y <= c) Union(a[i].id, (*it2).id); } } } int main(){ fread(buf, sizeof(char), sizeof(buf), stdin); ans = N = readint(); c = readint(); for(int x, y, i = 1; i <= N; i++){ x = readint(); y = readint(); a[i] = Node(x + y, x - y, i); } sort(a + 1, a + N + 1, cmp1()); for(int i = 1; i <= N; i++) fa[i] = i; solve(); int tot = 0; for(int i = 1; i <= N; i++){ cnt[Find(i)]++; if(cnt[Find(i)] > tot) tot = cnt[Find(i)]; } printf("%d %d ", ans, tot); return 0; }