BZOJ3775 : 点和直线

     设第$i$条直线的解析式为$a_ix+b_iy+c_i=0$,$d_i=a_i^2+b_i^2$,则要求一个点$(x,y)$,使得$\sum\left(\frac{\left|a_ix+b_iy+c_i\right|}{\sqrt{d_i}}\right)^2$最小。

            假设$x$固定,则

            \[\begin{eqnarray*}ans&=&\sum\left(\frac{\left|a_ix+b_iy+c_i\right|}{\sqrt{d_i}}\right)^2\\&=&\sum\frac{\left(a_ix+b_iy+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(b_iy+a_ix+c_i\right)^2}{d_i}\\&=&\sum\left(\frac{b_i^2y^2}{d_i}+\frac{2b_i\left(a_ix+c_i\right)y}{d_i}+\frac{\left(a_ix+c_i\right)^2}{d_i}\right)\\&=&\sum\frac{b_i^2y^2}{d_i}+\sum\frac{2b_i\left(a_ix+c_i\right)y}{d_i}+\sum\frac{\left(a_ix+c_i\right)^2}{d_i}\\&=&y^2\sum\frac{b_i^2}{d_i}+2y\sum\frac{b_i\left(a_ix+c_i\right)}{d_i}+\sum\frac{\left(a_ix+c_i\right)^2}{d_i}\\&=&y^2\sum\frac{b_i^2}{d_i}+2y\left(\sum\frac{a_ib_ix}{d_i}+\sum\frac{b_ic_i}{d_i}\right)+\sum\frac{\left(a_ix+c_i\right)^2}{d_i}\\&=&y^2\sum\frac{b_i^2}{d_i}+2y\left(x\sum\frac{a_ib_i}{d_i}+\sum\frac{b_ic_i}{d_i}\right)+\sum\frac{\left(a_ix+c_i\right)^2}{d_i}\end{eqnarray*}\]

            当$y$取对称轴时取得最小值,此时

            \[\begin{eqnarray*}y&=&-\frac{2\left(x\sum\frac{a_ib_i}{d_i}+\sum\frac{b_ic_i}{d_i}\right)}{2\sum\frac{b_i^2}{d_i}}\\&=&-\frac{x\sum\frac{a_ib_i}{d_i}+\sum\frac{b_ic_i}{d_i}}{\sum\frac{b_i^2}{d_i}}\\&=&-\frac{\sum\frac{a_ib_i}{d_i}}{\sum\frac{b_i^2}{d_i}}x-\frac{\sum\frac{b_ic_i}{d_i}}{\sum\frac{b_i^2}{d_i}}\\&=&Ax+B\\A&=&-\frac{\sum\frac{a_ib_i}{d_i}}{\sum\frac{b_i^2}{d_i}}\\B&=&-\frac{\sum\frac{b_ic_i}{d_i}}{\sum\frac{b_i^2}{d_i}}\end{eqnarray*}\]

            将$y$用$Ax+B$表示,则

            \[\begin{eqnarray*}ans&=&\sum\frac{\left(a_ix+b_iy+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(a_ix+b_i\left(Ax+B\right)+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(a_ix+Ab_ix+Bb_i+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(\left(a_i+Ab_i\right)x+Bb_i+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(a_i+Ab_i\right)^2x^2+2\left(a_i+Ab_i\right)\left(Bb_i+c_i\right)x+\left(Bb_i+c_i\right)^2}{d_i}\\&=&\sum\left( \frac{\left(a_i+Ab_i\right)^2x^2}{d_i}+\frac{2\left(a_i+Ab_i\right)\left(Bb_i+c_i\right)x}{d_i}+\frac{\left(Bb_i+c_i\right)^2}{d_i}\right)\\&=&x^2\sum\frac{\left(a_i+Ab_i\right)^2}{d_i}+2x\sum\frac{\left(a_i+Ab_i\right)\left(Bb_i+c_i\right)}{d_i}+\sum\frac{\left(Bb_i+c_i\right)^2}{d_i}\\&=&Ux^2+Vx+W\\U&=&\sum\frac{\left(a_i+Ab_i\right)^2}{d_i}\\&=&\sum\frac{a_i^2+2Aa_ib_i+A^2b_i^2}{d_i}\\&=&\sum\frac{a_i^2}{d_i}+2A\sum\frac{a_ib_i}{d_i}+A^2\sum\frac{b_i^2}{d_i}\\V&=&2\sum\frac{\left(a_i+Ab_i\right)\left(Bb_i+c_i\right)}{d_i}\\&=&2\sum\frac{Ba_ib_i+a_ic_i+ABb_i^2+Ab_ic_i}{d_i}\\&=&2\left(B\sum\frac{a_ib_i}{d_i}+\sum\frac{a_ic_i}{d_i}+AB\sum\frac{b_i^2}{d_i}+A\sum\frac{b_ic_i}{d_i}\right)\\W&=&\sum\frac{\left(Bb_i+c_i\right)^2}{d_i}\\&=&\sum\frac{B^2b_i^2+2Bb_ic_i+c_i^2}{d_i}\\&=&B^2\sum\frac{b_i^2}{d_i}+2B\sum\frac{b_ic_i}{d_i}+\sum\frac{c_i^2}{d_i}\end{eqnarray*}\]

            若$U=0$,则最小值为$W$,否则当$x$取对称轴时取得最小值,此时$x=-\frac{V}{2U}$,假设我们已经知道了$\sum\frac{a_i^2}{d_i},\sum\frac{b_i^2}{d_i},\sum\frac{c_i^2}{d_i},\sum\frac{a_ib_i}{d_i},\sum\frac{a_ic_i}{d_i},\sum\frac{b_ic_i}{d_i}$,则答案可以$O(1)$求出。

            对于修改操作,只要$O(1)$修改这六个值即可。

            至此,本题在$O(N)$复杂度内被解决。

#include<cstdio>
#include<cmath>
#define N 120010
int n,q,op,i,m;
double X1,X2,Y1,Y2,a,b,c,d,aa[N],bb[N],cc[N],ab[N],ac[N],bc[N],saa,sbb,scc,sab,sac,sbc,eps=1e-8,ans;
inline bool zero(double x){return std::fabs(x)<eps;}
inline double solve(double a,double b,double c){
  if(zero(a))return c;
  double x=-b/(2.0*a);
  return a*x*x+b*x+c;
}
int main(){
  scanf("%d",&q);
  while(q--){
    scanf("%d",&op);
    if(op==0){
      scanf("%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2);
      if(zero(X1-X2))a=1,b=0,c=-X1;else a=(Y2-Y1)/(X2-X1),b=-1,c=Y1-a*X1;
      d=a*a+b*b;
      aa[++n]=a*a/d,bb[n]=b*b/d,cc[n]=c*c/d,ab[n]=a*b/d,ac[n]=a*c/d,bc[n]=b*c/d;
      saa+=aa[n],sbb+=bb[n],scc+=cc[n],sab+=ab[n],sac+=ac[n],sbc+=bc[n];
      m++;
    }
    if(op==1){
      scanf("%d",&i);
      saa-=aa[i],sbb-=bb[i],scc-=cc[i],sab-=ab[i],sac-=ac[i],sbc-=bc[i];
      m--;
    }
    if(op==2){
      if(!m){puts("0.00");continue;}
      if(zero(sbb))a=b=0;else a=-sab/sbb,b=-sbc/sbb;
      ans=solve(saa+2.0*a*sab+a*a*sbb,2.0*(b*sab+sac+a*b*sbb+a*sbc),b*b*sbb+2.0*b*sbc+scc);
      if(zero(ans))ans=0;
      printf("%.2f\n",ans);
    }
  }
  return 0;
}

  

posted @ 2014-11-28 19:42  Claris  阅读(617)  评论(0编辑  收藏  举报