bzoj 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居——排序+贪心+set

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.
—————————————————————————————
这道题首先我们进行一个转化 就是 将每个点变成(sx=(x+y), sy=( x-y))
这样两点的曼哈顿距离就是 max( |sx1 – sx2|, |sy1 – sy2|)=max( x1-x2+y1-y2 ,  x1-x2-y1+y2 )
这个可以分类证明 分四类
1 x1>x2 &&y1>y2 那么 sx1-sx2 就是曼哈顿距离的正常表示方法 且sx1-sx2>sy1-sy2 
2 x1<x2&&y1<y2 因为是绝对值 所以其实形式是一样的 (同上)
3 x1>x2&&y1<y2  那么 |x1-x2|+|y1-y2| = x1-x2+y2-y1 就是 sy1-sy2 也易得 sy1-sy2>sx1-sx2
3 x1>x2&&y2>y1 一样是绝对值 倒一下就好了(同上)
这样之后我们把点按 sx 排序 维护一个队列 对头的坐标和当前点的坐标的sx的差 不能超过 c
因为超过 c 他必然不可能和当前点曼哈顿距离小于c
所以如果超过我们要删除(顺便在平衡树把这个点删了)
然后我们维护一个sy的平衡树 求一下当前点sy在平衡树里面的前驱后继 看一下能不能合并
如果可以就合并在一个并查集  最后扫一波就可以得到答案了
至于为什么可以这么合并 因为就算别的点在前驱的下面或者后继的下面并且他们可以和当前点合并
那么他们一定在之前和前驱后继或者是再前再后合并 所以这样的贪心是可行的
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
using namespace std;
const int M=150007;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,c;
int f[M],h[M],ans,mx;
int find(int x){while(f[x]!=x) x=f[x]=f[f[x]]; return x;}
struct node{
    int x,y,id;
    bool operator <(const node& k)const{return x<k.x;}
}e[M];
struct pos{
    int y,id;
    bool operator <(const pos& k)const{return y!=k.y?y<k.y:id<k.id;}
};
std::queue<int>q;
std::multiset<pos>tr;
std::multiset<pos>::iterator it;
int main(){
    int x,y;
    n=read(); c=read();
    for(int i=1;i<=n;i++){
        x=read(); y=read();
        f[i]=i; e[i].x=x+y,e[i].y=x-y; e[i].id=i;
    }
    sort(e+1,e+1+n);
    for(int i=1;i<=n;i++){
        while(!q.empty()&&e[i].x-e[q.front()].x>c){
            int now=q.front(); q.pop();
            tr.erase(tr.find((pos){e[now].y,e[now].id}));
        }
        q.push(i);
        it=tr.insert((pos){e[i].y,e[i].id});
        if(it!=tr.begin()){
            --it;
            if(e[i].y-(it->y)<=c){
                int p=find(e[i].id),q=find(it->id);
                f[q]=p;
            }
            ++it;
        }
        ++it;
        if(it!=tr.end()){
            if(it->y-e[i].y<=c){
                int p=find(e[i].id),q=find(it->id);
                f[q]=p;
            }
        }
    }
    for(int i=1;i<=n;i++){
        int x=find(e[i].id);
        if(!h[x]) ans++;
        h[x]++; mx=max(mx,h[x]);
    }printf("%d %d\n",ans,mx);
    return 0;
}
View Code

 

posted @ 2017-08-31 19:56  友人Aqwq  阅读(195)  评论(0编辑  收藏  举报