【bzoj1604】: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居

先是曼哈顿距离的变换
一维排序 另一维用splay维护前驱和后继 判断一下距离是否小于c 如果小于并查集并起来 就行了


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int N=210011;
const int inf=0x3f3f3f3f;
struct node{int x,y;}a[N];
struct Node{int l,r,fa,d;}sp[N];
int fa[N],size[N],root,cnt,vis[N];
int n,c;

int cmp(node x,node y)
{
  if(x.x==y.x)return x.y<y.y;
  return x.x<y.x;
}
int Find(int x)
{
    if(x==fa[x])return x;
    return fa[x]=Find(fa[x]);
}
void  merge(int x,int y)
{
   x=Find(x);
   y=Find(y);
   if(x==y)return;
   if(size[y]<size[x])swap(x,y);
   size[y]+=size[x];
   fa[x]=y; 
}
void zig(int x)
{
    int y=sp[x].fa;
    sp[y].l=sp[x].r;
    if(sp[x].r)sp[sp[x].r].fa=y;
    sp[x].fa=sp[y].fa;
    if(sp[y].fa)
    if(sp[sp[y].fa].l==y)sp[sp[y].fa].l=x;
    else sp[sp[y].fa].r=x;
    sp[x].r=y,sp[y].fa=x;
}
void zag(int x)
{
    int y=sp[x].fa;
    sp[y].r=sp[x].l;
    if(sp[x].l)sp[sp[x].l].fa=y;
    sp[x].fa=sp[y].fa;
    if(sp[y].fa)
    if(sp[sp[y].fa].l==y)sp[sp[y].fa].l=x;
    else sp[sp[y].fa].r=x;
    sp[x].l=y,sp[y].fa=x;
}
void splay(int x,int aim)
{
  while(sp[x].fa!=aim)
    {
         //cout<<x<<" "<<aim<<endl;
        int y=sp[x].fa;
        if(sp[y].fa==aim)
        {
            if(sp[y].l==x)zig(x);
            else zag(x);
        }
        else
        {
            if(sp[sp[y].fa].l==y)
            {
                if(sp[y].l==x)zig(y),zig(x);
                else zag(x),zig(x);
            }
            else
            {
                if(sp[y].r==x)zag(y),zag(x);
                else zig(x),zag(x);
            }
        }
    }
    if(aim==0)root=x;
}
int find(int x,int d,int ret)//返回小于等于d的数
{
    if(x==0)return ret;
    if(sp[x].d>d)return find(sp[x].l,d,ret);
    return find(sp[x].r,d,x);
}
int getnext(int x)
{ 
  x=sp[x].r;
  while(sp[x].l)x=sp[x].l;
  return x;
}
int getlast(int x)
{
    x=sp[x].l;
    while(sp[x].r)x=sp[x].r;
    return x;
}
void insert(int d,int xx)
{
   int x=find(root,d-1,0);
   splay(x,0);
   int y=getnext(x);
  // cout<<y<<" "<<x<<endl;
   splay(y,x);//cout<<"0.0";
   sp[y].l=xx;
   sp[xx].fa=y;
   sp[xx].d=d;
   if(sp[xx].d-sp[x].d<=c&&sp[x].d!=-inf)merge(xx,x);
   if(sp[y].d-sp[xx].d<=c&&sp[x].d!=inf)merge(xx,y);
}
void del(int x)
{
    splay(x,0);
    int xx=getlast(x);
    splay(xx,0);
    int y=getnext(x);
    //cout<<xx<<" "<<y<<endl;
    splay(y,xx);
    sp[y].l=0;
}
void bili()
{
  cnt=2;
  sp[n+1].d=inf;
  sp[2+n].d=-inf;
  sp[1+n].l=2+n;
  sp[2+n].fa=1+n;
  root=1+n; 
}
void debug(int x)
{
  if(!x)return;
  debug(sp[x].l);
  cout<<x<<" ";
  debug(sp[x].r);
}
int main()
{
   cin>>n>>c;
   for(int i=1;i<=n;i++)
   {
      int X,Y;
      scanf("%d%d",&X,&Y);
      a[i].x=X+Y,a[i].y=X-Y;
   }
   for(int i=1;i<=n;i++)fa[i]=i,size[i]=1;
   sort(a+1,a+1+n,cmp);
   bili();
    int l=1;
    for(int i=1;i<=n;i++)
    {

        while(l<=i&&a[i].x-a[l].x>c)del(l),l++;
        insert(a[i].y,i);
        //cout<<l<<" "<<i<<endl;
        //cout<<root<<endl;
        //debug(root);
        //cout<<endl;
    }

   int ans=0;
   int gs=0;
   for(int i=1;i<=n;i++)
   {
      int x=Find(i);
      if(vis[x]==0)vis[x]=1,gs++;
      ans=max(ans,size[x]);
   }
   printf("%d %d",gs,ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值