[Treap][并查集]牛的街区 Cow Neighborhoods

题目描述

奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l≤Xi,Yi≤10^9);Xi,Yi为整数.当满足下列两个条件之一,两只奶牛i和j是属于同一个群的:

1.两只奶牛的曼哈顿距离不超过C(1≤C≤10^9),即lXi – xil+IYi – Yil≤C.

2.两只奶牛有共同的邻居.即,存在一只奶牛k,使i与k,j与k均同属一个群.

给出奶牛们的位置,请计算草原上有多少个牛群,以及最大的牛群里有多少奶牛

输入:
第一行两个数N,C
接下来N行每行两个正整数xi,yi
(如题意)

输出:
两个整数一个表示街区的数量,另一个表示最多人(牛?)的街区的牛的数量

分析

首先某某和某某共群,容易想到并查集
然后容易想到每头牛只需要连比较近的就行了,因为求接近值,联想到平衡树的前驱后继
那么我们怎么比较牛比较近呢?
一开始我是想直接按以原点为参照的曼哈顿距离做,但是后面画了画图,不对。
然后想从曼哈顿距离本身开始考究,然后小小算了一下:
|x1-x2|+|y1-y2|=
当x1>x2,y1>y2时
x1+y1-x2-y2
当x1

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <queue>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int cnt,rt;
int f[100001],b[100001];
struct point
{
    int x,y,num;
}a[100001];
struct node
{
    int l,r;
    int size,key;
    point data;
}t[100001];

void UPDATE(int x)
{
    t[x].size=t[t[x].l].size+t[t[x].r].size+1;
}

void RIGHT_ROTATE(int &x)
{
    int y=t[x].l;
    t[x].l=t[y].r;t[y].r=x;
    UPDATE(x);UPDATE(y);
    x=y;
}

void LEFT_ROTATE(int &x)
{
    int y=t[x].r;
    t[x].r=t[y].l;t[y].l=x;
    UPDATE(x);UPDATE(y);
    x=y;
}

void INSERT(int &x,point data)
{
    if (x==0)
    {
        x=++cnt;
        t[x].size=1;
        t[x].data.x=data.x;
        t[x].data.y=data.y;
        t[x].data.num=data.num;
        t[x].key=rand();
        return;
    }
    if (data.y<=t[x].data.y)
    {
        INSERT(t[x].l,data);
        if (t[t[x].l].key>t[x].key) RIGHT_ROTATE(x);
    }
    else
    {
        INSERT(t[x].r,data);
        if (t[t[x].r].key>t[x].key) LEFT_ROTATE(x);
    }
    UPDATE(x);
}

void DELETE(int &x,point data)
{
    if (x==0) return;
    if (t[x].data.y==data.y)
    {
        if (t[x].l||t[x].r)
        {
            if (t[x].l&&(!t[x].r||t[t[x].l].key<t[t[x].r].key))
            {
                RIGHT_ROTATE(x);
                DELETE(t[x].r,data);
            }
            else
            {
                LEFT_ROTATE(x);
                DELETE(t[x].l,data);
            }
            UPDATE(x);
        }
        else x=0;
        return;
    }
    if (data.y<t[x].data.y) DELETE(t[x].l,data);
    else DELETE(t[x].r,data);
    UPDATE(x);
}

point GET_PRE(int data)
{
    int x=rt;
    point ans;
    ans.x=0;ans.y=-2147483647;ans.num=-1;
    while (x)
    {
        if (t[x].data.y<=data)
        {
            if (t[x].data.y>ans.y)
            {
                ans.y=t[x].data.y;
                ans.num=t[x].data.num;
            }
            x=t[x].r;
        }
        else x=t[x].l;
    }
    return ans;
}

point GET_NEXT(int data)
{
    int x=rt;
    point ans;
    ans.x=0;ans.y=2147483647;ans.num=-1;
    while (x)
    {
        if (t[x].data.y>=data)
        {
            if (t[x].data.y<ans.y)
            {
                ans.y=t[x].data.y;
                ans.num=t[x].data.num;
            }
            x=t[x].l;
        }
        else x=t[x].r;
    }
    return ans;
}

int GET_F(int x)
{
    if (f[x]==x) return x;
    return f[x]=GET_F(f[x]);
}

void MERGE(int x,int y)
{
    int i=GET_F(x),j=GET_F(y);
    f[i]=j;
}

bool CMP(point a,point b)
{
    return a.x<b.x;
}

int main()
{
    int n,i;
    long long c;
    int x,y;
    scanf("%d%lld",&n,&c);
    rep(i,1,n)
    {
        scanf("%d%d",&x,&y);
        a[i].x=x+y;a[i].y=x-y;a[i].num=i;
        f[i]=i;
    }
    sort(a+1,a+n+1,CMP);
    queue<point> q;
    while (!q.empty()) q.pop();
    q.push(a[1]);
    INSERT(rt,a[1]);
    rep(i,2,n)
    {
        point p=q.front();
        while (abs(p.x-a[i].x)>c&&!q.empty())
        {
            q.pop();
            DELETE(rt,p);
            p=q.front();
        }
        point pre=GET_PRE(a[i].y),next=GET_NEXT(a[i].y);
        if ((long long)a[i].y-pre.y<=c) MERGE(a[i].num,pre.num);
        if ((long long)next.y-a[i].y<=c) MERGE(a[i].num,next.num);
        INSERT(rt,a[i]);
        q.push(a[i]);
    }
    int cnt=0,ans=0;
    rep(i,1,n)
    b[GET_F(i)]++;
    rep(i,1,n)
    if (b[i])
    {
        cnt++;
        ans=max(ans,b[i]);
    }
    printf("%d %d",cnt,ans);
}

猜你喜欢

转载自blog.csdn.net/ssl_qyh0ice/article/details/80634521
今日推荐