BZOJ 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居:队列 + multiset + 并查集【曼哈顿距离变形】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1604
题意:
平面直角坐标系中,有n个点(n <= 100000,坐标范围10^9)。
给定r,当两个点的曼哈顿距离<=r时,认为这两个点在同一个“群”中。
问你共有多少个群,以及点的数量最多的群有多少个点。
题解:
本题的核心在于:如何枚举一个点周围满足“曼哈顿距离<=r”的点。
由于 曼哈顿距离 = |x1 - x2| + |y1 - y2|。
x和y相互影响,不能单纯按x或y排序,枚举所有点总复杂度为O(N^2)。
所以要用到曼哈顿距离的另一种形式:
设X = x + y , Y = x - y
d(曼哈顿距离) = max(|X1-X2|, |Y1-Y2|)
将每个点的X = x + y,Y = x - y,这就将X与Y的关系分离开了。
将所有点按X排序。
当前考虑到点i。
用一个队列(X升序),保证队列中的所有X满足要求,否则不断删去队首。
用一个multiset(Y升序),找到i的前驱pre和后继suc,如果i与pre(或suc)的Y满足要求,则合并(并查集)。
最后统计一下每个群就好了。
AC Code:
1 // |x1-x2| + |y1-y2| 2 // | (x1+y1) - (x2+y2) | 3 // | (x1-y1) - (x2-y2) | 4 // X = x + y 5 // Y = x - y 6 // d = max(|X1-X2|, |Y1-Y2|) <= r 7 #include <iostream> 8 #include <stdio.h> 9 #include <string.h> 10 #include <algorithm> 11 #include <set> 12 #define MAX_N 100005 13 #define INF 100000000 14 15 using namespace std; 16 17 struct Coor 18 { 19 int x; 20 int y; 21 int idx; 22 Coor(int _x,int _y,int _idx) 23 { 24 x=_x; 25 y=_y; 26 idx=_idx; 27 } 28 Coor(){} 29 friend bool operator < (const Coor &a,const Coor &b) 30 { 31 return a.y!=b.y?a.y<b.y:a.idx<b.idx; 32 } 33 }; 34 35 int n,r; 36 int ans=1; 37 int counter=0; 38 int head=0; 39 int par[MAX_N]; 40 int cnt[MAX_N]; 41 Coor c[MAX_N]; 42 multiset<Coor> mst; 43 44 inline bool cmp_x(const Coor &a,const Coor &b) 45 { 46 return a.x<b.x; 47 } 48 49 void init_union_find() 50 { 51 for(int i=0;i<n;i++) 52 { 53 par[i]=i; 54 } 55 } 56 57 int find(int x) 58 { 59 return par[x]==x?x:par[x]=find(par[x]); 60 } 61 62 void unite(int x,int y) 63 { 64 int px=find(x); 65 int py=find(y); 66 if(px==py) return; 67 par[px]=py; 68 } 69 70 void read() 71 { 72 cin>>n>>r; 73 int a,b; 74 for(int i=0;i<n;i++) 75 { 76 cin>>a>>b; 77 c[i].x=a+b; 78 c[i].y=a-b; 79 c[i].idx=i; 80 } 81 } 82 83 void solve() 84 { 85 init_union_find(); 86 sort(c,c+n,cmp_x); 87 mst.insert(Coor(0,INF,0)); 88 mst.insert(Coor(0,-INF,0)); 89 mst.insert(c[head]); 90 for(int i=1;i<n;i++) 91 { 92 while(c[i].x-c[head].x>r) 93 { 94 mst.erase(c[head]); 95 head++; 96 } 97 multiset<Coor>::iterator it=mst.lower_bound(c[i]); 98 Coor suc=*it; 99 Coor pre=*--it; 100 if(c[i].y-pre.y<=r) unite(pre.idx,c[i].idx); 101 if(suc.y-c[i].y<=r) unite(suc.idx,c[i].idx); 102 mst.insert(c[i]); 103 } 104 memset(cnt,0,sizeof(cnt)); 105 for(int i=0;i<n;i++) 106 { 107 int p=find(i); 108 if(cnt[p]==0) counter++; 109 cnt[p]++; 110 ans=max(ans,cnt[p]); 111 } 112 } 113 114 void print() 115 { 116 cout<<counter<<" "<<ans<<endl; 117 } 118 119 int main() 120 { 121 read(); 122 solve(); 123 print(); 124 }