[玄学分治 || 线段树] BZOJ 2675 Bomb & Tsin 1322 Bomb(李超)

来源:互联网 发布:淘宝客怎么算恶意下单 编辑:程序博客网 时间:2024/05/20 09:11

玄学分治做法 %%% http://www.cnblogs.com/ccz181078/p/5603283.html


三个点(x1,y1),(x2,y2),(x3,y3)的两两曼哈顿距离和为2(max(x1,x2,x3)+max(y1,y2,y3)-min(x1,x2,x3)-min(y1,y2,y3))

四项三个点 由抽屉原理 必至少有两项是同一个点的

那么最大值就是

max((x+y)max-xmin-ymin,xmax+ymax-(x+y)min,(x-y)max-xmin+ymax,xmax-ymin-(x-y)min)


最小值分治跟最近点对很相似

这里为了防卡 把xy交换了


#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>using namespace std;inline char nc(){  static char buf[100000],*p1=buf,*p2=buf;  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }  return *p1++;}inline void read(int &x){  char c=nc(),b=1;  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}const int N=100005;struct Point{  int x,y;  void read(){    ::read(x); ::read(y);  }  bool operator < (const Point &B)const {    return x==B.x?y<B.y:x<B.x;  }}P[N],tmp[N];int pnt=0;bool cmp(Point A,Point B){  return A.y==B.y?A.x<B.x:A.y<B.y;}inline int Calc(Point A,Point B,Point C){  return max(A.x,max(B.x,C.x))-min(A.x,min(B.x,C.x))+max(A.y,max(B.y,C.y))-min(A.y,min(B.y,C.y));}int n;int Ans=1<<30;inline void Solve(int l,int r){  if (r-l<15){    for (int i=l;i<=r;i++) for (int j=i+1;j<=r;j++) for (int k=j+1;k<=r;k++) Ans=min(Ans,Calc(P[i],P[j],P[k]));    return;  }  int mid=(l+r)>>1;  Solve(l,mid); Solve(mid,r);  pnt=0;  for (int i=mid;i<=r;i++) if (abs(P[i].x-P[mid].x)<Ans) tmp[++pnt]=P[i]; else break;  for (int i=mid-1;i>=l;i--) if (abs(P[i].x-P[mid].x)<Ans) tmp[++pnt]=P[i]; else break;  sort(tmp+1,tmp+pnt+1,cmp);  int L=1,R;  for (R=3;R<=pnt;R++){    while (abs(tmp[R].y-tmp[L].y)>=Ans) L++;    for (int j=L;j<R;j++)      for (int k=j+1;k<R;k++)Ans=min(Ans,Calc(tmp[j],tmp[k],tmp[R]));  }}int main(){  int xmax,xmin,ymax,ymin,xpymax,xpymin,xmymax,xmymin;  freopen("t.in","r",stdin);  freopen("t.out","w",stdout);  xmax=ymax=xpymax=xmymax=-1<<30;  xmin=ymin=xpymin=xmymin=1<<30;  read(n);  for (int i=1;i<=n;i++){    P[i].read(); swap(P[i].x,P[i].y);    xmax=max(xmax,P[i].x),xmin=min(xmin,P[i].x);    ymax=max(ymax,P[i].y),ymin=min(ymin,P[i].y);    xpymax=max(xpymax,P[i].x+P[i].y),xpymin=min(xpymin,P[i].x+P[i].y);    xmymax=max(xmymax,P[i].x-P[i].y),xmymin=min(xmymin,P[i].x-P[i].y);  }  printf("%d\n",2*max(max(xpymax-xmin-ymin,xmax+ymax-xpymin),max(xmymax-xmin+ymax,xmax-ymin-xmymin)));  sort(P+1,P+n+1);  Solve(1,n);  printf("%d\n",Ans*2);  return 0; }


这道题正解是不是线段树啊 

我想了想三个点的相对位置 一共七八种吧 好麻烦

不过Claris把坐标转来转去 最终发现不对称的只有两种了

厉害啊
http://www.cnblogs.com/clrs97/p/4872267.html



跟最近点对很相似
0 0