【bzoj1604】【Usaco2008 Open】Cow Neighborhoods (set+曼哈顿距离性质+并查集)奶牛的邻居

题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=1604
题解:
首先要做这道题我们知道曼哈顿距离的一个性质,那就是:
如果原来坐标是(x, y),令新的坐标为(X, Y), 其中X = x + y, Y = x - y
曼哈顿距离 = |x1 - x2| + |y1 - y2| = max ( |X1 - X2|, |Y1 - Y2| );
还有就是如何运用set,这个百度里可以搜到,看这个东西大概可以知道set怎么用
http://baike.baidu.com/link?url=uVFabYTc3qYwwhKfxKuS-vfAFSKYQquK8iEq4vVrRXyFDm8Ps9oH_GADc6Lfs40cTLfbjfXhnMVLRL-NtnnN4q
接下来就是这道题的关键点,如何判断哪些点在同一个块中:
首先我们将给出的每个点的坐标用(x+y , x-y)来表示,这样的话按新的x坐标从小到大排序,维护一个队列满足队首到队尾的X坐标(X=x+y)距离小于c,这样的话 max ( |X1 - X2|, |Y1 - Y2| ) 中 |X1 - X2| 就满足小于c了,如何满足 |Y1 - Y2| 也小于c呢,我们需要用到平衡树即set,如果新加入元素在set中的前驱后继与它的Y值差值不超过c,则用并查集将他们连在一起,set本身有好多用法,可以参照上面给出的网页。
代码:

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const ll inf=1e16;
struct node{
    ll x;ll y;int id;
}a[100005];
int c,n,fa[100005],cnt[100005];
multisets;
node jia(ll xx,ll yy,int idd)
{
    node tmp;
    tmp.x=xx;tmp.y=yy;tmp.id=idd;
    return tmp;
}
int cmp(node x,node y)
{
    if (x.x!=y.x)
    return x.xreturn x.ybool operator < (const node a, const node b)
{
    return a.y < b.y;
}
int find(int x)
{
    if (fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}
int num;
void unio(int x,int y)
{
    //cout<
    int X=find(x);
    int Y=find(y);
    if (X!=Y)
    {
        fa[X]=Y;
        num--;
    }
}
int main()
{
    scanf("%d%d",&n,&c);num=n;
    for (int i=1;i<=n;i++)
    {
        ll x,y;
        fa[i]=i;
        scanf("%lld%lld",&x,&y);
        a[i].x=x+y;a[i].y=x-y;
        a[i].id=i;
    }
    sort(a+1,a+1+n,cmp);
    s.insert(jia(0,inf,0));
    s.insert(jia(0,-inf,0));
    s.insert(a[1]);
    int head=1;
    node l,r;
    for (int i=2;i<=n;i++)
    {
        while(a[i].x-a[head].x>c)
        {
            s.erase(s.find(a[head]));
            head++;
        }
        set  ::iterator it=s.lower_bound(a[i]);
        r=*it;it--;l=*it;
        if (a[i].y-l.y<=c)
        unio(a[i].id,l.id);
        if (r.y-a[i].y<=c)
        unio(a[i].id,r.id);
        s.insert(a[i]);
    }
    int sum=-1;
    for (int i=1;i<=n;i++)
    {
        int tmp=find(i);
        cnt[tmp]++;
        sum=max(sum,cnt[tmp]);
    }
    printf("%d %d\n",num,sum);
}

你可能感兴趣的:(bzoj)