BZOJ 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的鄰居:佇列 + multiset + 並查集【曼哈頓距離變形】

Leohh發表於2017-09-26

題目連結: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 }

 

相關文章