BZOJ3775 : 点和直线

时间:2022-04-17 16:02:20

    设第$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;
}