题目描述
奶牛喜欢成群结队.观察约翰的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);
}