bzoj 1604 奶牛的邻居

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.



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.
 
 
思路:我们把点对坐标转化为(x+y,x-y),那么曼哈顿距离就转化为了max(|x1-x2|,|y1-y2|); 我们把点按照x坐标排序,然后维护一个队列,队列中元素的x坐标差的绝对值是不大于C的。然后用平衡树(或者multiset),维护y坐标,每次查找y坐标前驱后继,并检验y坐标差值是否大于C,如果不大于,就可以用并查集连接当前点和其y坐标前驱后继,最后通过统计并查集数量和每个并查集大小来得到答案。
 
 1 #include<bits/stdc++.h>
 2 using namespace std;  
 3 #define R register int
 4 #define rep(i,a,b) for(R i=a;i<=b;i++) 
 5 #define Rep(i,a,b) for(R i=a;i>=b;i--) 
 6 #define ms(i,a)    memset(a,i,sizeof(a))
 7 template<class T>void read(T &x){
 8     x=0; char c=0;  
 9   while (!isdigit(c)) c=getchar();  
10   while (isdigit(c)) x=x*10+(c^48),c=getchar();  
11 }
12 int const N=100003;  
13 struct node{
14   int vy,id;  
15   bool operator < (const node & rhs) const{
16     if(vy!=rhs.vy) return vy<rhs.vy;  
17     else return id<rhs.id;  
18   }
19 };  
20 struct cow{
21   int x,y;   
22   bool operator< (const cow &rhs) const{
23     return x<rhs.x;  
24   }
25 }a[N];  
26 int n,c,f[N],sz[N],vis[N],ans;  
27 set<node> s;   
28 set<node> :: iterator p; 
29 int gf(int x){return x==f[x]?  x:f[x]=gf(f[x]);}  
30 void un(int x,int y){
31   int fx=gf(x),fy=gf(y);  
32   if(fx==fy) return ;
33   f[fx]=fy; sz[fy]+=sz[fx];ans--; 
34 }
35 int main(){
36   read(n); read(c);  ans=n;  
37   rep(i,1,n){
38     int x,y; read(x); read(y); 
39     a[i].x=x+y;a[i].y=x-y;   
40   }
41   sort(a+1,a+n+1);  
42   rep(i,1,n) f[i]=i,sz[i]=1;  
43   int k=1;    
44   rep(i,1,n){
45     while (a[i].x-a[k].x>c){
46       node t=(node){a[k].y,k}; k++;  s.erase(t);  
47     }
48     node t;t.vy=a[i].y;t.id=i; 
49     p=s.lower_bound(t);   
50     if(p!=s.end()){
51       if(p->vy-a[i].y<=c) un(i,p->id);  
52       if(p!=s.begin()){
53         --p; if(a[i].y-p->vy<=c)  un(i,p->id);  
54       }  
55     }else if(s.size()){
56       p=--s.end();  
57       if(a[i].y-p->vy<=c) un(i,p->id);
58     }
59     s.insert(t); 
60   }
61   int maxs=0;  
62   rep(i,1,n) {
63     int fx=gf(i);   
64     if(vis[fx]) continue;  
65     vis[fx]=1;  
66     maxs=max(maxs,sz[fx]);   
67   }
68   cout<<ans<<" "<<maxs<<endl; 
69   return 0; 
70 }
View Code

 

转载于:https://www.cnblogs.com/ZJXXCN/p/10204309.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值