[USACO08OPEN]牛的街区Cow Neighborhoods

题目描述:

luogu

题解:

技巧题。

曼哈顿距离:$|x1-x2|+|y1-y2|$

切比雪夫距离:$\max(|x1-x2|,|y1-y2|)$

曼哈顿距离转切比雪夫距离:$(x,y)->(x+y,x-y)$

所以……排完序拿stl::set模拟就好了。

代码:

#include<set>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 100050;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,c,ff[N],siz[N];
int findff(int x){return x==ff[x]?x:ff[x]=findff(ff[x]);}
void merge(int x,int y)
{
    x = findff(x),y = findff(y);
    if(x!=y)ff[x] = y,siz[y]+=siz[x];
}
struct Point
{
    ll x,y;int id;
    Point(){}
    Point(ll x,ll y):x(x),y(y){}
    bool operator < (const Point&a)const{return x!=a.x?x<a.x:y<a.y;}
}p[N];
bool cmp(Point a,Point b){return a.y!=b.y?a.y<b.y:a.x<b.x;}
set<Point>tr;
int main()
{
    read(n),read(c);ll x,y;
    for(int i=1;i<=n;i++)
    {
        read(x),read(y);
        p[i] = Point(x+y,x-y);
    }
    sort(p+1,p+1+n,cmp);
    for(int i=1;i<=n;i++)
        siz[i]=1,ff[i]=i,p[i].id=i;
    set<Point>::iterator it;Point now;
    for(int i=1,j=1;i<=n;i++)
    {
        while(p[i].y-p[j].y>c)tr.erase(p[j]),j++;
        it = tr.lower_bound(p[i]);
        if(it!=tr.end())
        {
            now=(*it);
            if(now.x-p[i].x<=c)merge(now.id,i);
        }
        if(it!=tr.begin())
        {
            it--;now=(*it);
            if(p[i].x-now.x<=c)merge(now.id,i);
        }
        tr.insert(p[i]);
    }
    int ans1 = 0,ans2 = -1;
    for(int i=1;i<=n;i++)
        if(findff(i)==i)ans1++,ans2=max(ans2,siz[i]);
    printf("%d %d\n",ans1,ans2);
    return 0;
}
View Code

 

posted @ 2019-06-26 23:33  LiGuanlin  阅读(145)  评论(0编辑  收藏  举报