根据题意,发现题目中的图,其实就是一颗树或者是一颗基环树,每个节点上有一个点对\((x,y)\),每次询问为给定端点,找一条直线到端点间的所有点的距离之和最小。

设这条直线为\(y=kx+b\),根据点到直线公式得,我们要求\(\sum\limits_{i=1}^n \frac{(kx_i-y_i+b)^2}{k^2+1}\)的最小值,其中\(n\)为路径上的点的个数。

然后开始处理这个式子:

\[\begin{aligned}
&\sum\frac{(kx_i-y_i+b)^2}{k^2+1} \\

=&\sum\frac{(kx_i-y_i)^2+2(kx_i-y_i)b+b^2}{k^2+1} \\

=&\sum\frac{k^2x_i^2-2kx_iy_i+y_i^2+2kbx_i-2by_i+b^2}{k^2+1} \\

=&\frac{\sum k^2x_i^2-\sum 2kx_iy_i+\sum y_i^2+\sum 2kbx_i-\sum 2by_i+nb^2}{k^2+1} \\
\end{aligned}
\]

发现对于直线\(y=kx+b\),\(k\)和\(b\)的取值是互不影响的,所以可以先对\(b\)进行处理,使其取到能让式子达到最小值的值,然后代入原式,再求\(k\)能让式子达到最小值的值。

先对含有\(b\)的项进行分类,得:

\[\frac{nb^2+\sum (2kx_i-2y_i)b+\sum (k^2x_i^2-2kx_iy_i+y_i^2)}{k^2+1}
\]

考虑\(b\)作为变量,发现其为开口向上的二次函数,当\(b= \frac{\sum (2y_i-2kx_i)}{2n}=\frac{\sum y_i}{n}-\frac{\sum kx_i}{n}\),发现\(\frac{\sum x_i}{n}\)的意义就是对于所有\(x_i\)的平均值,所以设\(\bar x=\frac{\sum x_i}{n},\bar y=\frac{\sum y_i}{n}\),将\(b=\bar y-k \bar x\)代入原式,得:

\[\frac{\sum k^2x_i^2-\sum 2kx_iy_i+\sum y_i^2+\sum 2k(\bar y-k \bar x)x_i-\sum 2(\bar y-k \bar x)y_i+n(\bar y-k \bar x)^2}{k^2+1} \\
\]

然后像上面一样,对含有\(k\)的项进行分类,得:

\[\frac{\sum (x_i^2-2x_i \bar x+ \bar x^2)k^2+\sum(-2x_iy_i+2x_i \bar y+2 \bar x y_i -2 \bar x \bar y)k+\sum (y_i^2-2y_i \bar y+ \bar y^2)}{k^2+1}
\]

为方便接下来的处理,设出\(k\)的系数:

\[\begin{aligned}
&A=\sum (x_i^2-2x_i \bar x+ \bar x^2)=\sum x_i^2-\frac{(\sum x_i)^2}{n}\\

&B=\sum(-2x_iy_i+2x_i \bar y+2 \bar x y_i -2 \bar x \bar y)=-2\sum x_iy_i+\frac{2\sum x_i\sum y_i}{n}\\

&C=\sum (y_i^2-2y_i \bar y+ \bar y^2)=\sum y_i^2-\frac{(\sum y_i)^2}{n}\\
\end{aligned}
\]

设原式的值为\(S\),得:

\[\begin{aligned}
&S=\frac{Ak^2+Bk+C}{k^2+1}\\

&Sk^2+S=Ak^2+Bk+C\\

&(A-S)k^2+Bk+C-S=0\\
\end{aligned}
\]

发现得到一个关于\(k\)的一元二次方程,因为\(k\)一定会有合法解,所以得:

\[\begin{aligned}
\Delta&=B^2-4(A-S)(C-S) \geqslant 0\\

&=B^2-4AC+4AS+4CS-4S^2 \geqslant 0\\

&=-4S^2+4(A+C)S+B^2-4AC \geqslant 0\\
\end{aligned}
\]

发现得到一个关于\(S\)的一元二次不等式,将其看作开口向下的二次函数,得其值必须大于等于\(0\),所以\(S\)的最小取值即为其方程的较小根,得:

\[\begin{aligned}
&S=\frac{A+C-\sqrt{A^2+B^2+C^2-2AC}}{2}\\

&A=\sum x_i^2-\frac{(\sum x_i)^2}{n}\\

&B=-2\sum x_iy_i+\frac{2\sum x_i\sum y_i}{n}\\

&C=\sum y_i^2-\frac{(\sum y_i)^2}{n}\\

\end{aligned}
\]

然后维护每个点到根节点\(\sum x_i,\sum y_i,\sum x_i^2,\sum y_i^2,\sum x_iy_i,n\)的和,然后就可以通过树上差分求解了。对于基环树的情况,若两点在一个子树内,就直接树上差分,若两点不在一个子树内,需要经过环,则从经过环的两种方式得出的两个值取较小值作为答案。

\(code:\)

  1. #include<bits/stdc++.h>
  2. #define maxn 400010
  3. using namespace std;
  4. template<typename T> inline void read(T &x)
  5. {
  6. x=0;char c=getchar();bool flag=false;
  7. while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
  8. while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
  9. if(flag)x=-x;
  10. }
  11. int n,m,q,tot;
  12. int de[maxn],f[maxn][25],fa[maxn],a[maxn],b[maxn];
  13. int cir[maxn],bel[maxn],pos[maxn];
  14. bool flag;
  15. bool tag[maxn];
  16. struct edge
  17. {
  18. int to,nxt;
  19. }e[maxn];
  20. int head[maxn],edge_cnt;
  21. void add(int from,int to)
  22. {
  23. e[++edge_cnt]=(edge){to,head[from]};
  24. head[from]=edge_cnt;
  25. }
  26. struct node
  27. {
  28. int x,y,xd,yd,mul,num;
  29. void insert(int a,int b)
  30. {
  31. x+=a,y+=b,xd+=a*a,yd+=b*b,mul+=a*b,num++;
  32. }
  33. double calc()
  34. {
  35. double A=xd-(double)x*x/num,B=-2*mul+2*(double)x*y/num,C=yd-(double)y*y/num;
  36. return (A+C-sqrt(A*A+B*B+C*C-2*A*C))/2;
  37. }
  38. }s[maxn],sum[maxn];
  39. node operator +(const node &a,const node &b)
  40. {
  41. return (node){a.x+b.x,a.y+b.y,a.xd+b.xd,a.yd+b.yd,a.mul+b.mul,a.num+b.num};
  42. }
  43. node operator -(const node &a,const node &b)
  44. {
  45. return (node){a.x-b.x,a.y-b.y,a.xd-b.xd,a.yd-b.yd,a.mul-b.mul,a.num-b.num};
  46. }
  47. int find(int x)
  48. {
  49. return fa[x]==x?x:fa[x]=find(fa[x]);
  50. }
  51. void dfs(int x,int fath,int col)
  52. {
  53. f[x][0]=fath,de[x]=de[fath]+1,bel[x]=col,s[x]=s[fath],s[x].insert(a[x],b[x]);
  54. for(int i=1;i<=18;++i) f[x][i]=f[f[x][i-1]][i-1];
  55. for(int i=head[x];i;i=e[i].nxt)
  56. {
  57. int y=e[i].to;
  58. if(y==fath||tag[y]) continue;
  59. dfs(y,x,col);
  60. }
  61. }
  62. int lca(int x,int y)
  63. {
  64. if(de[x]<de[y]) swap(x,y);
  65. for(int i=18;i>=0;--i)
  66. if(de[f[x][i]]>=de[y])
  67. x=f[x][i];
  68. if(x==y) return x;
  69. for(int i=18;i>=0;--i)
  70. if(f[x][i]!=f[y][i])
  71. x=f[x][i],y=f[y][i];
  72. return f[x][0];
  73. }
  74. void dfs_cir(int x,int fath)
  75. {
  76. if(tag[x]&&x!=cir[1])
  77. {
  78. flag=true;
  79. return;
  80. }
  81. for(int i=head[x];i;i=e[i].nxt)
  82. {
  83. int y=e[i].to;
  84. if(y==fath) continue;
  85. if(tag[x]&&tag[y]) continue;
  86. cir[++tot]=y,dfs_cir(y,x);
  87. if(flag) return;
  88. tot--;
  89. }
  90. }
  91. double solve(int x,int y)
  92. {
  93. int anc=lca(x,y);
  94. return (s[x]+s[y]-s[anc]-s[f[anc][0]]).calc();
  95. }
  96. int main()
  97. {
  98. read(n),read(m);
  99. for(int i=1;i<=n;++i) read(a[i]),read(b[i]),fa[i]=i;
  100. for(int i=1;i<=m;++i)
  101. {
  102. int x,y;
  103. read(x),read(y),add(x,y),add(y,x);
  104. if(find(x)==find(y)) cir[++tot]=x,tag[x]=tag[y]=true;
  105. else fa[find(x)]=find(y);
  106. }
  107. if(m==n-1) dfs(1,0,0);
  108. else
  109. {
  110. dfs_cir(cir[1],0);
  111. for(int i=1;i<=tot;++i)
  112. {
  113. int x=cir[i];
  114. pos[x]=i,tag[x]=true;
  115. sum[i]=sum[i-1],sum[i].insert(a[x],b[x]);
  116. }
  117. for(int i=1;i<=tot;++i) dfs(cir[i],0,cir[i]);
  118. }
  119. read(q);
  120. while(q--)
  121. {
  122. int x,y;
  123. read(x),read(y);
  124. if(m==n-1) printf("%.6lf\n",solve(x,y));
  125. else
  126. {
  127. if(bel[x]==bel[y]) printf("%.6lf\n",solve(x,y));
  128. else
  129. {
  130. int px=pos[bel[x]],py=pos[bel[y]];
  131. node val=s[x]+s[y]-s[bel[x]]-s[bel[y]];
  132. if(px>py) swap(px,py);
  133. printf("%.6lf\n",min((val+sum[py]-sum[px-1]).calc(),(val+sum[tot]-sum[py-1]+sum[px]).calc()));
  134. }
  135. }
  136. }
  137. return 0;
  138. }

题解 洛谷 P3340 【[ZJOI2014]星系调查】的更多相关文章

  1. bzoj 3528 [ZJOI2014] 星系调查 题解

    [原题] 星系调查 [问题描写叙述] 银河历59451年.在银河系有许很多多已被人类殖民的星系.如果想要在行 星系间往来,大家一般使用连接两个行星系的跳跃星门.  一个跳跃星门能够把 物质在它所连接的 ...

  2. [洛谷P3338] [ZJOI2014]力

    洛谷题目链接:P3338 [ZJOI2014]力 题目描述 给出n个数qi,给出Fj的定义如下: \[F_j = \sum_{i<j}\frac{q_i q_j}{(i-j)^2 }-\sum_ ...

  3. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  4. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  5. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  6. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

  7. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  8. 题解-洛谷P4859 已经没有什么好害怕的了

    洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ...

  9. 题解-洛谷P5217 贫穷

    洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ...

随机推荐

  1. 【论文笔记】Pyramidal Convolution: Rethinking Convolutional Neural Networks for Visual Recognition

    地址:https://arxiv.org/pdf/2006.11538.pdf github:https://github.com/iduta/pyconv 目前的卷积神经网络普遍使用3×3的卷积神经 ...

  2. Celery浅谈

    一.Celery 核心模块 1. Brokers brokers 中文意思为中间人,在这里就是指任务队列本身,接收生产者发来的消息即Task,将任务存入队列.任务的消费者是Worker,Brokers ...

  3. IDEA2019版中文汉化包

    废话不多说,上才艺   E G M~~~~~ 2020版的IDEA大佬可以无视........ 1.打开IDEA文件目录 2.打开lib目录--将汉化版复制到该目录下 3.打开IDEA查看效果 高铁链 ...

  4. git和github入门指南(5)

    5.github上的标签 5.1.标签的作用 给当前版本打一个标签,在github上就会形成一个releases版本 点击进去后,用户就可以下载对应版本的源代码 5.2.在本地git工具上创建标签,同 ...

  5. 关于for循环和Iterator遍历ArrayList的性能问题

    今日看到@DriveMan的一篇博客,题为<ArrayList集合实现RandomAccess接口有何作用?为何LinkedList集合却没实现这接口?>,文中提到对于实现了RandomA ...

  6. Python之浅谈模块

    目录 模块的四种形式 什么是模块 import和from......import 循环导入 模块的搜索路径 Python文件的两种用途 random模块 模块的四种形式 什么是模块 ​ 模块就是一个p ...

  7. 安装pymysql模块及使用

    安装pymysql模块: https://www.cnblogs.com/Eva-J/articles/9772614.html file--settings for New Projects---P ...

  8. rpm部分命令解读

    rpm部分命令解读 rpm---RedHat Package Manger---打包及安装工具 rpm参数列表   rpm -a rpm -q < rpm package name> 解读 ...

  9. 「线段树」「单点修改」洛谷P1198 [JSOI2008]最大数

    「线段树」「单点修改」洛谷P1198 [JSOI2008]最大数 题面描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数, ...

  10. Django---进阶2

    目录 数据的查,改,删 django orm中如何创建表关系 django请求生命周期流程图(必会) 路由层 路由匹配 无名分组 有名分组 无名有名是否可以混合使用 反向解析 作业 数据的查,改,删 ...