【USACO 2008 Open Gold】 3.Cow Neighborhoods 平衡树、并查集

来源:互联网 发布:刷点卷的软件 编辑:程序博客网 时间:2024/05/17 08:09

题解:

首先曼哈顿距离有些不好维护,但是它可以转化:

一个点本来的坐标是(x,y),那么可以转化成(x+y,x-y)

这样就人为构造出一种性质:1、2两点曼哈顿距离=max(|x1-x2|,|y1-y2|);


这样我们就可以排序单调搞掉一维,然后另一维只需要求前驱后继到该点的距离

满足则加并查集。


这个过程可以用权值线段树,也可以用平衡树。但是权值线段树还需要离散化,反而代码多了。


代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 101000#define ls son[x][0]#define rs son[x][1]#define is(x) (x==son[fa[x]][1])#define inf 0x3f3f3f3fusing namespace std;struct Point{int x,y;bool operator < (const Point &a)const{return x==a.x?y<a.y:x<a.x;}}p[N];int n,m;int f[N];int find(int x){return f[x]==x?x:f[x]=find(f[x]);}struct SPT{int son[N][2],fa[N],root,cnt;int val[N],id[N],size[N];void pushup(int x){size[x]=size[ls]+size[rs]+1;}void link(int x,int y,int d){son[y][d]=x,fa[x]=y;}void rotate(int x){int y=fa[x],z=fa[y],i=is(x),t=son[x][!i];link(t,y,i),link(x,z,is(y)),link(y,x,!i);fa[0]=0;pushup(y);}void splay(int x,int k=0){int y,z;while(fa[x]!=k){y=fa[x],z=fa[y];if(z==k){rotate(x);break;}rotate(is(x)==is(y)?y:x),rotate(x);}pushup(x);if(!k)root=x;return ;}void newnode(int &x,int y,int w,int p){x=p;fa[p]=y,ls=rs=0;val[p]=w,size[p]=1;}void cls(){root=fa[cnt=2]=1,son[1][1]=2;val[1]=-inf,val[2]=inf;size[1]=2,size[2]=1;}int pred(int x,int k=0){splay(x);for(x=ls;rs;)x=rs;splay(x,k);return x;}int succ(int x,int k=0){splay(x);for(x=rs;ls;)x=ls;splay(x,k);return x;}void remove(int x){pred(x);splay(x,root);link(rs,root,1);}void insert(int w){int x=root;for(;son[x][val[x]<w];x=son[x][val[x]<w]);newnode(son[x][val[x]<w],x,w,++cnt);splay(son[x][val[x]<w]);}void solve(int w){insert(w);int pr=pred(cnt),su=succ(cnt);if(abs(val[pr]-w)<=m)f[find(pr)]=cnt;if(abs(val[su]-w)<=m)f[find(su)]=cnt;}}spt;int num[N],nn,ans;int main(){int i,j,k;scanf("%d%d",&n,&m);if(m<=0){printf("%d 1\n",n);return 0;}for(i=1;i<=n;i++)scanf("%d%d",&j,&k),p[i].x=j+k,p[i].y=j-k;for(i=3;i<=n+2;i++)f[i]=i;sort(p+1,p+n+1);spt.cls();int l=1,r;for(r=1;r<=n;r++){while(p[r].x-p[l].x>m)spt.remove(2+l++);spt.solve(p[r].y);}for(i=3;i<=n+2;i++)num[find(i)]++;for(i=3;i<=n+2;i++)if(num[i])nn++,ans=max(ans,num[i]);printf("%d %d\n",nn,ans);return 0;}


0 0