【bzoj1604】[Usaco2008 Open]Cow Neighborhoods奶牛的邻居
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行输入N和C,之后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 3OUTPUT 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.
题目分析:曼哈顿距离的一种巧妙转化:令A[i]=x[i]+y[i],B[i]=x[i]-y[i],abs(x[i]-x[j])+abs(y[i]-y[j])=max(abs(A[i]-A[j]),abs(B[i]-B[j]))。这样我们就把两个abs相加转变为了两个abs取max,它们是独立的了。于是我们用排序搞定其中一维,然后从左到右扫,用treap维护即可。我们每处理一个点,只需要将A小于等于它且差值不超过c的点的B值加进treap里(为什么不需要考虑A值比它大的?因为两个点i,j,一定有一个被先处理到,我们只要由后处理到的向先处理到的连边就不会重复遗漏),然后和它的前驱后继连边(因为后继的后继已经和后继连了边,就不需要再由它向后继连边了)。
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
#include<ctime>
using namespace std;
const int maxn=100100;
const int oo=2000000001;
struct Tnode
{
int val,fix;
int id,Size;
Tnode *lson,*rson;
} tree[maxn];
Tnode *root=NULL;
int cur=-1;
struct data
{
int x,y;
} cow[maxn];
int fa[maxn];
int _Size[maxn];
bool Root[maxn];
int n,c;
bool Comp(data p,data q)
{
return p.x<q.x;
}
Tnode *New_node(int nid,int v)
{
cur++;
tree[cur].val=v;
tree[cur].fix=rand();
tree[cur].id=nid;
tree[cur].Size=1;
tree[cur].lson=tree[cur].rson=NULL;
return tree+cur;
}
void Recount(Tnode *&P)
{
int temp=1;
if (P->lson) temp+=P->lson->Size;
if (P->rson) temp+=P->rson->Size;
P->Size=temp;
}
void Right_turn(Tnode *&P)
{
Tnode *W=P->lson;
P->lson=W->rson;
W->rson=P;
P=W;
Recount(P->rson);
Recount(P);
}
void Left_turn(Tnode *&P)
{
Tnode *W=P->rson;
P->rson=W->lson;
W->lson=P;
P=W;
Recount(P->lson);
Recount(P);
}
void Insert(Tnode *&P,int nid,int v)
{
if (!P) P=New_node(nid,v);
else if ( v<P->val || ( v==P->val && nid<P->id ) )
{
Insert(P->lson,nid,v);
if ( P->lson->fix < P->fix ) Right_turn(P);
}
else
{
Insert(P->rson,nid,v);
if ( P->rson->fix < P->fix ) Left_turn(P);
}
Recount(P);
}
void Delete(Tnode *&P,int nid,int v)
{
if ( v==P->val && nid==P->id )
{
if ( P->lson && P->rson )
{
if ( P->lson->fix < P->rson->fix )
{
Right_turn(P);
Delete(P->rson,nid,v);
}
else
{
Left_turn(P);
Delete(P->lson,nid,v);
}
Recount(P);
}
else if (P->lson) P=P->lson;
else if (P->rson) P=P->rson;
else P=NULL;
}
else
{
if ( v<P->val || ( v==P->val && nid<P->id ) ) Delete(P->lson,nid,v);
else Delete(P->rson,nid,v);
Recount(P);
}
}
int Get_rank(Tnode *P,int nid,int v)
{
int left_size=0;
if (P->lson) left_size=P->lson->Size;
if ( v==P->val && nid==P->id ) return left_size+1;
else if ( v<P->val || ( v==P->val && nid<P->id ) ) return Get_rank(P->lson,nid,v);
else return left_size+1+Get_rank(P->rson,nid,v);
}
int Abs(int v)
{
if (v>=0) return v;
return -v;
}
int Query(Tnode *P,int rank,int v)
{
if ( rank==0 || rank>P->Size ) return 0;
int left_size=0;
if (P->lson) left_size=P->lson->Size;
if (rank<=left_size) return Query(P->lson,rank,v);
else if (rank==left_size+1)
{
if ( Abs(v-P->val)<=c ) return P->id;
else return 0;
}
else return Query(P->rson,rank-left_size-1,v);
}
void Up(int p)
{
if (p==fa[p]) return;
Up(fa[p]);
fa[p]=fa[ fa[p] ];
}
void Add(int p,int q)
{
Up(p);
Up(q);
if (fa[p]==fa[q]) return;
_Size[ fa[q] ]+=_Size[ fa[p] ];
fa[ fa[p] ]=fa[q];
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
srand( time(0) );
scanf("%d%d",&n,&c);
for (int i=1; i<=n; i++)
{
int a,b;
scanf("%d%d",&a,&b);
cow[i].x=a+b;
cow[i].y=a-b;
}
sort(cow+1,cow+n+1,Comp);
for (int i=1; i<=n; i++)
{
fa[i]=i;
_Size[i]=1;
}
int temp=1;
Insert(root,1,cow[1].y);
for (int i=2; i<=n; i++)
{
Insert(root,i,cow[i].y);
while (cow[i].x-cow[temp].x>c)
{
Delete(root,temp,cow[temp].y);
temp++;
}
int rank=Get_rank(root,i,cow[i].y);
int last=Query(root,rank-1,cow[i].y);
int Next=Query(root,rank+1,cow[i].y);
if (last) Add(last,i);
if (Next) Add(Next,i);
}
for (int i=1; i<=n; i++) Up(i);
for (int i=1; i<=n; i++) Root[ fa[i] ]=true;
int num=0,max_size=0;
for (int i=1; i<=n; i++) if (Root[i])
{
num++;
max_size=max(max_size,_Size[i]);
}
printf("%d %d\n",num,max_size);
//for (int i=1; i<=n; i++) printf("%d ",fa[i]);
//printf("\n");
return 0;
}