Online JudgeCodeforces629ELuogu-CF629E

Label:树上计数,分类讨论,换根

题目描述

给出一棵n个节点的树。有m个询问,每一个询问包含两个数a、b,我们可以对任意两个不相连的点连一条无向边,并且使得加上这条边后a,b处在一个环内。对于每一个询问,求这样的环的期望长度。

\(2<=n,m<=10^5\)

输入

第一行包括两个整数n,m,分别表示节点数和询问数。

接下来n-1行,每行两个整数u、v表示有一条从u到v的边。

接下来m行,每行两个整数a、b(a≠b),表示一个询问。

输出

对于每一个询问,输出满足条件的环的期望长度。答案保留6位小数。

样例

Input#1

  1. 4 3
  2. 2 4
  3. 4 1
  4. 3 2
  5. 3 1
  6. 2 3
  7. 4 1

Output#1

  1. 4.00000000
  2. 3.00000000
  3. 3.00000000

Input#2

  1. 3 3
  2. 1 2
  3. 1 3
  4. 1 2
  5. 1 3
  6. 2 3

Output#2

  1. 2.50000000
  2. 2.50000000
  3. 3.00000000

题解

题目求的是期望,其实就是求两个东西,\(all=\)能形成环的个数,\(ans=\)所有环的长度总和,两者相除得到答案。

转化为树上的计数问题。接下来分两种情况讨论。

先交代下面会用到的数组,及其意义。

\(sz[x]\):以x为根的子树所含节点的个数。

\(dep[x]\):节点深度。

\(fa[x][i=0..17]\):x向上第\(2^i\)个祖先(供后面倍增跳LCA用)。

\(sum[x]\):\(= ∑_{son∈x}dep[son]\),也就是子树中所有点的深度之和。

\(tot[x]\):后面再说。

1.(u,v)不是祖先关系

发现只能将u,v子树里的点连起来。

所以,能形成环的个数\(all=sz[u]*sz[v]\),其中\(sz\)数组表示子树所含节点个数。

所有环的长度之和:

\[ans+=sz[u]*(sum[v]-dep[v]*sz[v]);\\ans+=sz[v]*(sum[u]-dep[u]*sz[u]);\\ans+=all*(dep[u]+dep[v]-2*dep[lca]+1);(lca是指u,v的LCA)
\]

根据图很容易理解。


2.(u,v)是祖先关系

特殊点说明:将深度小的点作为u。son是u的儿子中通向v的那一个。v是深度较大的那一个。

如何求son?倍增向上跳\(dep[v]-dep[u]-1\)步,可以在O(logN)时间内得到。


看下面这幅图,我们只能在v的子树中选一个点,在蓝色部分(除子树son的点)选一个点,将两者相连,才能形成环。

所以,环的个数\(all=sz[v]*(sz[1]-sz[son])\)。

如何求环的长度总和?分成下面几部分分步求解。

这里换个元方便下面表示\(sz1=sz[v]\),\(sz2=(sz[1]-sz[son])\)。\(sz1\)就是粉色部分的点数,\(sz2\)就是蓝色部分的点数。

part1:

\(ans+=(sum[v]-dep[v]*sz1)*sz2+(dep[v]-dep[u])*all\)

part2:

\(ans+=1*all\)

part3:

这个东西与前面几个相比不太好分析。

求树上两点(a,b)的距离就是\(dep[a]+dep[b]-2*dep[LCA(a,b)]\)。

全部加起来,那么现在我们求的就是下面这东西。

\[dep[u]*sz2+∑_{x∈bluepart}(dep[x]-2*dep[LCA(u,x)])
\]

前面那个可以O(1)算出。就是后面那一坨如何在可行的时间内弄出?

考虑预处理一个数组\(tot[son]\),表示,若它的父亲节点为u,则\(tot[son]=∑_{x∈bluepart}(dep[x]-2*dep[LCA(u,x)])\)也就是上面式子中后面的部分。

dfs一遍,完成\(tot\)数组的预处理,转移如下。画个图还是很好理解的,当弄到x时,f就是上式的lca。

  1. void dfs2(int x){
  2. int f=fa[x][0];
  3. if(f){
  4. tot[x]=tot[f]+sum[f]-sum[x];
  5. tot[x]-=2ll*(sz[f]-sz[x])*dep[f];
  6. }
  7. for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa[x][0])dfs2(e[i].to);
  8. }

综上分两种情况讨论,时间复杂度为\(O(NlogN)\)。

完整代码如下:

  1. //原题CF629E
  2. #include<bits/stdc++.h>
  3. #define int long long
  4. using namespace std;
  5. typedef long long ll;
  6. const int N=1e5+10;
  7. inline int read(){
  8. int x=0;char c=getchar();
  9. while(c<'0'||c>'9')c=getchar();
  10. while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
  11. return x;
  12. }
  13. struct edge{
  14. int to,nxt;
  15. }e[N<<1];
  16. int head[N],ecnt;
  17. inline void link(int u,int v){
  18. e[++ecnt].to=v,e[ecnt].nxt=head[u];
  19. head[u]=ecnt;
  20. }
  21. int n,m;
  22. ll sum[N],tot[N];
  23. int sz[N],dep[N],fa[N][18];
  24. ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
  25. void dfs(int x,int f){
  26. fa[x][0]=f,dep[x]=dep[f]+1,sum[x]=dep[x];
  27. sz[x]=1;
  28. for(int i=head[x];i;i=e[i].nxt){
  29. int y=e[i].to;if(y==f)continue;
  30. dfs(y,x);
  31. sz[x]+=sz[y];
  32. sum[x]+=sum[y];
  33. }
  34. }
  35. void dfs2(int x){
  36. int f=fa[x][0];
  37. if(f){
  38. tot[x]=tot[f]+sum[f]-sum[x];
  39. tot[x]-=2ll*(sz[f]-sz[x])*dep[f];
  40. }
  41. for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa[x][0])dfs2(e[i].to);
  42. }
  43. inline int jump(int x,int stp){
  44. for(int i=0;i<=17;i++)if(stp&(1<<i))x=fa[x][i];
  45. return x;
  46. }
  47. inline int LCA(int x,int y){
  48. if(dep[x]<dep[y])swap(x,y);
  49. int stp=dep[x]-dep[y];
  50. x=jump(x,stp);
  51. if(x==y)return x;
  52. for(int i=17;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
  53. return fa[x][0];
  54. }
  55. signed main(){
  56. n=read(),m=read();
  57. for(int i=1;i<n;i++){
  58. int u=read(),v=read();
  59. link(u,v),link(v,u);
  60. }
  61. dfs(1,0),dfs2(1);
  62. for(int j=1;j<=17;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
  63. while(m--){
  64. int u=read(),v=read();
  65. if(dep[u]>dep[v])swap(u,v);
  66. int lca=LCA(u,v);
  67. ll all,ans;
  68. if(lca==u){
  69. int son=jump(v,dep[v]-dep[u]-1);
  70. int sz1=sz[v],sz2=sz[1]-sz[son];
  71. all=1ll*sz1*sz2,ans=0;
  72. ans+=1ll*(sum[v]-dep[v]*sz1)*sz2;
  73. ans+=1ll*(tot[son]+sz2*dep[u])*sz1;
  74. ans+=1ll*all*(dep[v]-dep[u]+1);
  75. }
  76. else{
  77. all=1ll*sz[u]*sz[v],ans=0;
  78. ans+=1ll*sz[u]*(sum[v]-dep[v]*sz[v]);
  79. ans+=1ll*sz[v]*(sum[u]-dep[u]*sz[u]);
  80. ans+=1ll*all*(dep[u]+dep[v]-2*dep[lca]+1);
  81. }
  82. //ll g=gcd(all,ans);
  83. //printf("%lld/%lld\n",ans/g,all/g);
  84. printf("%.7f\n",1.0*ans/all);
  85. }
  86. }

CF629E Famil Door and Roads【树上计数+分类讨论】的更多相关文章

  1. Codeforces Round #343 (Div. 2) E. Famil Door and Roads lca 树形dp

    E. Famil Door and Roads 题目连接: http://www.codeforces.com/contest/629/problem/E Description Famil Door ...

  2. Bzoj4558:分类讨论 计算几何 组合数学

    国际惯例的题面: 这题让我爆肝啦......这种计数显然容斥,正好不含任何坏点的我们不会算,但是我们能算至少含零个坏点的,至少含一个坏点的,至少含两个坏点的......所以最终的答案就是(至少含零个坏 ...

  3. bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论

    题目大意 1.将x到当前根路径上的所有点染成一种新的颜色: 2.将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根: 3.查询以x为根的子树中所有点权值的平均值. 分析 原题codec ...

  4. P5979 [PA2014]Druzyny dp 分治 线段树 分类讨论 启发式合并

    LINK:Druzyny 这题研究了一下午 终于搞懂了. \(n^2\)的dp很容易得到. 考虑优化.又有大于的限制又有小于的限制这个非常难处理. 不过可以得到在限制人数上界的情况下能转移到的最远端点 ...

  5. Codeforces 521E - Cycling City(点双连通分量+分类讨论)

    Codeforces 题面传送门 & 洛谷题面传送门 大家都是暴力找生成树然后跳路径,代码不到 50 行(暴论)的一说--好,那本蒟蒻决定提供一种代码 150 行,但复杂度也是线性的分类讨论做 ...

  6. Codeforces 460D Little Victor and Set --分类讨论+构造

    题意:从区间[L,R]中选取不多于k个数,使这些数异或和尽量小,输出最小异或和以及选取的那些数. 解法:分类讨论. 设选取k个数. 1. k=4的时候如果区间长度>=4且L是偶数,那么可以构造四 ...

  7. BZOJ-1067 降雨量 线段树+分类讨论

    这道B题,刚的不行,各种碎点及其容易忽略,受不鸟了直接 1067: [SCOI2007]降雨量 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 2859 ...

  8. UVaLive 6862 Triples (数学+分类讨论)

    题意:给定一个n和m,问你x^j + y^j = z^j 的数量有多少个,其中0 <= x <= y <= z <= m, j = 2, 3, 4, ... n. 析:是一个数 ...

  9. 枚举(分类讨论):BZOJ 1177: [Apio2009]Oil

    1177: [Apio2009]Oil Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1477  Solved: 589[Submit] Descri ...

随机推荐

  1. es5 JSON对象

    1. JSON.stringify(obj/arr) js对象(数组)转换为json对象(数组) 2. JSON.parse(json) json对象(数组)转换为js对象(数组) <!DOCT ...

  2. kubernetes忘记token或者token过期怎么加入k8s集群

    1.先查看token是否还可用 [root@hadoop01 ~]# kubeadm token list 1.1) 还在则获取ca证书sha256编码hash值,不在则进行2操作 openssl x ...

  3. python和go对比字符串的链式处理

    一.什么是链式处理 对数据的操作进行多步骤的处理称为链式处理,链式处理器是一种常见的编程设计,链式处理的开发思想将数据和操作拆分,解耦,让开发者可以根据自己的技术优势和需求,进行系统开发,同时将自己的 ...

  4. Kmeans算法实现

    下面的demo是根据kmeans算法原理实现的demo,使用到的数据是kmeans.txt 1.658985 4.285136 -3.453687 3.424321 4.838138 -1.15153 ...

  5. PAT甲级——A1131 Subway Map【30】

    In the big cities, the subway systems always look so complex to the visitors. To give you some sense ...

  6. Android基础知识—Context理解及使用

    Context是Android中一个非常重要的概念,用于访问全局信息,几乎所有的基础组件都继承自 Context,理解 Context 对于学习 Android 四大基本组件非常有帮助. 1. Con ...

  7. Java中关于注释、标识符、变量、常量、数据类型、类型转换、转移字符以及数值型的表现形式的详解

    Java文件的注意事项 在同一个Java文件中,可以定义多个类,但是被public修饰的类只能够有一个,并且此类名要与文件名一致. 在同一个类中,可以定义多个方法,但是名字叫做main的方法只能有一个 ...

  8. Bootstrap——可拖动模态框(Model)

    还是上一个小项目,o(╥﹏╥)o,要实现点击一个div或者button或者一个东西然后可以弹出一个浮在最上面的弹框.网上找了找,发现Bootstrap的Model弹出框可以实现该功能,因此学习了一下, ...

  9. [NOIP2019模拟赛]夹缝

    夹缝 问题描述: 二维空间内有两面相对放置的,向无限远延伸的镜子,以镜子的方向及其法向量建立坐标系,我们选定一个法向量方向下面称“上”.在镜子上的整数位置,存在着一些传感器,传感器不影响光线的反射,光 ...

  10. node中没有全局作用域,只有模块作用域(文件作用域)

    node中没有全局作用域,只有模块作用域(文件作用域)