标签:usaco 2008 open gold cow neighborhoods 前驱后继 平衡树 并查集
题解:
首先曼哈顿距离有些不好维护,但是它可以转化:
一个点本来的坐标是(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 0x3f3f3f3f using 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; }
【USACO 2008 Open Gold】 3.Cow Neighborhoods 平衡树、并查集
标签:usaco 2008 open gold cow neighborhoods 前驱后继 平衡树 并查集
原文地址:http://blog.csdn.net/vmurder/article/details/42340085