[Usaco2008 Open]Cow Neighborhoods 奶牛的邻居

1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居

Time Limit: 5 Sec   Memory Limit: 64 MB
Submit: 656   Solved: 248
[ Submit][ Status][ Discuss]

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行输入NC,之后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.



由于本人智商问题这玩意儿困扰了我好久。。。

看了网上大牛的解释对于曼哈顿距离做如下处理:

  设任意两点坐标分别为(x1,y1)与(x2,y2)

  两点曼哈顿距离有四种情况:

  x1 - x2 + y1 - y2

  x1 - x2 + y2 - y1

  x2 - x1 + y1 - y2

  x2 - x1 + y2 - y1

  设X  = x + y,Y = x - y

  于是上述四个式子简化为max(|X1 - X2|,|Y1 - Y2|)

  然后维护X的同时将每个Y写入treap就好啦。。

  (每个点看看在treap的前驱后继能不能连边就是咯)

//对于我的代码。。没事开long long就WA,生气用int结果AC了。。真是呵呵哒

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<cstdlib>
#include<map>
#include<cmath>
#include<set>
using namespace std;


const int maxn = 5e5 + 10;
const int INF = 2e9 + 10;


typedef int LL;


struct P{
LL x,y;
bool operator < (const P &b) const{
return x + y < b.x + b.y;

}poi[maxn];


LL n,i,j,father[maxn],c,Size = 0,Max = 0,Siz[maxn];


queue <LL> q;


LL fa (LL k)
{
return k == father[k]?k:father[k] = fa(father[k]);
}


class data{

private :

struct Node{
Node *ch[2];
LL key,pri,N;
}pool[maxn],*root,*tot;

LL pos (Node *a,LL N)
{
LL N_key = poi[N].x - poi[N].y;
if (a -> key > N_key) return 0;
if (a -> key < N_key) return 1;
if (a -> N < N) return 1;
if (a -> N > N) return 0;
return -1;
}

void rotate (Node *&x,LL d)
{
Node *y = x -> ch[d];
x -> ch[d] = y -> ch[d^1];
y -> ch[d^1] = x;
x = y;
}

void Insert (Node *&x,LL N,LL pri)
{
LL key = poi[N].x - poi[N].y;
if (x == NULL)
{
x = tot++;
x -> key = key;
x -> N = N;
x -> pri = pri;
return;
}
LL d = pos(x,N);
Insert(x -> ch[d],N,pri);
if (x -> ch[d] -> pri > x -> pri) rotate(x,d);
}

void Remove(Node *&x,LL N)
{
LL d = pos(x,N);
if (d == -1)
{
if (x -> ch[0] != NULL && x -> ch[1] != NULL)
{
LL d2 = x -> ch[0] -> pri > x -> ch[1] -> pri?0:1;
rotate(x,d2);
Remove(x -> ch[d2^1],N);
}
else {
if (x -> ch[0] == NULL && x -> ch[1] == NULL)
{
x = NULL;
return;
}
if (x -> ch[0] == NULL) x = x -> ch[1];
else x = x -> ch[0];
}
}
else Remove(x -> ch[d],N);
}

LL find_pre(LL N)
{
Node *x = root;
LL N_key = poi[N].x - poi[N].y;
LL Max = -INF - 10,ret;
while (x != NULL)
{
if (x -> key == N_key) return x -> N;
LL d = pos(x,N);
if (x -> key < N_key && x -> key > Max) Max = x -> key,ret = x -> N;
x = x -> ch[d];
}
return ret;
}

LL find_next(LL N)
{
Node *x = root;
LL N_key = poi[N].x - poi[N].y;
LL Min = INF + 10,ret;
while (x != NULL)
{
LL d = pos(x,N);
if (x -> key == N_key) return x -> N;
if (x -> key > N_key && x -> key < Min) Min = x -> key,ret = x -> N;
x = x -> ch[d];
}
return ret;
}
public :

data () {
root = NULL;
tot = pool;
}

void Ins (LL N) {
Insert (root,N,rand());
}

void Rem (LL N) {
Remove (root,N);
}

LL F_P (LL N) {
return find_pre(N);
}

LL F_N (LL N) {
return find_next(N);
}
};
int main()
{
#ifndef ONLINE_JUDGE
#ifndef YZY
 freopen(".in","r",stdin);
 freopen(".out","w",stdout);
#else
 freopen("yzy.txt","r",stdin);
#endif
#endif

static data tree;
cin >> n >> c;
for (i = 1; i <= n; i++)
{
scanf("%d%d",&poi[i].x,&poi[i].y);
father[i] = i;
Siz[i] = 1;

father[n + 1] = n + 1;
father[0] = 0;
poi[n + 1].x = INF;
poi[n + 1].y = 0;
poi[0].x = -INF;
poi[0].y = 0;
tree.Ins(0);
tree.Ins(n + 1);
sort (poi + 1,poi + n + 1);
for (i = 1; i <= n; i++)
{
while (!q.empty())
{
   LL I_key = poi[i].x + poi[i].y;
LL k = q.front();
LL k_key = poi[k].x + poi[k].y;
if (I_key - k_key > c) tree.Rem(k),--Size,q.pop();
else break;
}
if (Size >= 1)
{
LL Pre = tree.F_P(i);
LL Next = tree.F_N(i);
LL f_p = fa(Pre),p_key = poi[Pre].x - poi[Pre].y;
LL f_i = fa(i),i_key = poi[i].x - poi[i].y;
if (f_p != f_i && abs(p_key - i_key) <= c && Pre != 0)
{
father[f_p] = f_i;
Siz[f_i] += Siz[f_p];
}
LL f_n = fa(Next),n_key = poi[Next].x - poi[Next].y;
if (f_n != f_i && Next != n + 1 && abs(n_key - i_key) <= c)
{
father[f_n] = f_i;
Siz[f_i] += Siz[f_n];
}
}
tree.Ins(i);
++Size;
q.push(i);
}
LL ans = 0;
for (i = 1; i <= n; i++)
 if (father[i] == i)
 {
  ++ans;
  Max = max(Siz[i],Max);
 }
printf("%d %d",ans,Max);
return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值