CF629E Famil Door and Roads【树上计数+分类讨论】
Online Judge:Codeforces629E,Luogu-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
4 3
2 4
4 1
3 2
3 1
2 3
4 1
Output#1
4.00000000
3.00000000
3.00000000
Input#2
3 3
1 2
1 3
1 2
1 3
2 3
Output#2
2.50000000
2.50000000
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\)数组表示子树所含节点个数。
所有环的长度之和:
\]
根据图很容易理解。
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)]\)。
全部加起来,那么现在我们求的就是下面这东西。
\]
前面那个可以O(1)算出。就是后面那一坨如何在可行的时间内弄出?
考虑预处理一个数组\(tot[son]\),表示,若它的父亲节点为u,则\(tot[son]=∑_{x∈bluepart}(dep[x]-2*dep[LCA(u,x)])\)也就是上面式子中后面的部分。
dfs一遍,完成\(tot\)数组的预处理,转移如下。画个图还是很好理解的,当弄到x时,f就是上式的lca。
void dfs2(int x){
int f=fa[x][0];
if(f){
tot[x]=tot[f]+sum[f]-sum[x];
tot[x]-=2ll*(sz[f]-sz[x])*dep[f];
}
for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa[x][0])dfs2(e[i].to);
}
综上分两种情况讨论,时间复杂度为\(O(NlogN)\)。
完整代码如下:
//原题CF629E
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int N=1e5+10;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x;
}
struct edge{
int to,nxt;
}e[N<<1];
int head[N],ecnt;
inline void link(int u,int v){
e[++ecnt].to=v,e[ecnt].nxt=head[u];
head[u]=ecnt;
}
int n,m;
ll sum[N],tot[N];
int sz[N],dep[N],fa[N][18];
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
void dfs(int x,int f){
fa[x][0]=f,dep[x]=dep[f]+1,sum[x]=dep[x];
sz[x]=1;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;if(y==f)continue;
dfs(y,x);
sz[x]+=sz[y];
sum[x]+=sum[y];
}
}
void dfs2(int x){
int f=fa[x][0];
if(f){
tot[x]=tot[f]+sum[f]-sum[x];
tot[x]-=2ll*(sz[f]-sz[x])*dep[f];
}
for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa[x][0])dfs2(e[i].to);
}
inline int jump(int x,int stp){
for(int i=0;i<=17;i++)if(stp&(1<<i))x=fa[x][i];
return x;
}
inline int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y);
int stp=dep[x]-dep[y];
x=jump(x,stp);
if(x==y)return x;
for(int i=17;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
signed main(){
n=read(),m=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
link(u,v),link(v,u);
}
dfs(1,0),dfs2(1);
for(int j=1;j<=17;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
while(m--){
int u=read(),v=read();
if(dep[u]>dep[v])swap(u,v);
int lca=LCA(u,v);
ll all,ans;
if(lca==u){
int son=jump(v,dep[v]-dep[u]-1);
int sz1=sz[v],sz2=sz[1]-sz[son];
all=1ll*sz1*sz2,ans=0;
ans+=1ll*(sum[v]-dep[v]*sz1)*sz2;
ans+=1ll*(tot[son]+sz2*dep[u])*sz1;
ans+=1ll*all*(dep[v]-dep[u]+1);
}
else{
all=1ll*sz[u]*sz[v],ans=0;
ans+=1ll*sz[u]*(sum[v]-dep[v]*sz[v]);
ans+=1ll*sz[v]*(sum[u]-dep[u]*sz[u]);
ans+=1ll*all*(dep[u]+dep[v]-2*dep[lca]+1);
}
//ll g=gcd(all,ans);
//printf("%lld/%lld\n",ans/g,all/g);
printf("%.7f\n",1.0*ans/all);
}
}
CF629E Famil Door and Roads【树上计数+分类讨论】的更多相关文章
- 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 ...
- Bzoj4558:分类讨论 计算几何 组合数学
国际惯例的题面: 这题让我爆肝啦......这种计数显然容斥,正好不含任何坏点的我们不会算,但是我们能算至少含零个坏点的,至少含一个坏点的,至少含两个坏点的......所以最终的答案就是(至少含零个坏 ...
- bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论
题目大意 1.将x到当前根路径上的所有点染成一种新的颜色: 2.将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根: 3.查询以x为根的子树中所有点权值的平均值. 分析 原题codec ...
- P5979 [PA2014]Druzyny dp 分治 线段树 分类讨论 启发式合并
LINK:Druzyny 这题研究了一下午 终于搞懂了. \(n^2\)的dp很容易得到. 考虑优化.又有大于的限制又有小于的限制这个非常难处理. 不过可以得到在限制人数上界的情况下能转移到的最远端点 ...
- Codeforces 521E - Cycling City(点双连通分量+分类讨论)
Codeforces 题面传送门 & 洛谷题面传送门 大家都是暴力找生成树然后跳路径,代码不到 50 行(暴论)的一说--好,那本蒟蒻决定提供一种代码 150 行,但复杂度也是线性的分类讨论做 ...
- Codeforces 460D Little Victor and Set --分类讨论+构造
题意:从区间[L,R]中选取不多于k个数,使这些数异或和尽量小,输出最小异或和以及选取的那些数. 解法:分类讨论. 设选取k个数. 1. k=4的时候如果区间长度>=4且L是偶数,那么可以构造四 ...
- BZOJ-1067 降雨量 线段树+分类讨论
这道B题,刚的不行,各种碎点及其容易忽略,受不鸟了直接 1067: [SCOI2007]降雨量 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 2859 ...
- UVaLive 6862 Triples (数学+分类讨论)
题意:给定一个n和m,问你x^j + y^j = z^j 的数量有多少个,其中0 <= x <= y <= z <= m, j = 2, 3, 4, ... n. 析:是一个数 ...
- 枚举(分类讨论):BZOJ 1177: [Apio2009]Oil
1177: [Apio2009]Oil Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 1477 Solved: 589[Submit] Descri ...
随机推荐
- python 模块间的引入
转载来自: https://www.cnblogs.com/whitemouseV2-0/p/9925344.html https://www.cnblogs.com/whitemouseV2-0/p ...
- 登录操作(方法二:for与else搭配)
登录操作(方法二:for与else搭配) user_name="star"passwoed='123' count=0for i in range(3): u_username=i ...
- javascript和jquery
JavaScript 1.概述 JavaScript是一种基于对象和事件驱动,并具有安全性能的脚本语言. 2.语法 HTML 中的脚本必须位于 <script> 与 </script ...
- <jquery>滚动例子
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- spring的mvc对于页面日期格式进行传值到后台
对于spring的mvc 日期格式从页面传入后台是个问题.string类型和整形都能友好传入.但是对于日期类型date却不能传入.回报403参数不对的错误. 看例子: @RequestMapping( ...
- 打开新窗口(window.open) open() 方法可以查找一个已经存在或者新建的浏览器窗口。 语法: window.open([URL], [窗口名称], [参数字符串])
打开新窗口(window.open) open() 方法可以查找一个已经存在或者新建的浏览器窗口. 语法: window.open([URL], [窗口名称], [参数字符串]) 参数说明: URL: ...
- ASP.NET中的DEC加密解密过程
本文章分享自 青青果树园的博客,地址是:http://www.cnblogs.com/qqingmu/archive/2008/01/10/1034168.html 我们做网页时经常会遇到URL传输( ...
- Luogu P2458 [SDOI2006]保安站岗(树形dp)
P2458 [SDOI2006]保安站岗 题意 题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下 ...
- git sync tags with remote
git 同步遠程標籤 在 .git/config的 [remote "origin"] 下加了 fetch = +refs/tags/*:refs/tags/* 最後就變成 [re ...
- [记]Windows 系统下设置Nodejs NPM全局路径
Windows下的Nodejs npm路径是appdata,担心安装的node_modules越来越多,导致C盘满,所以参考别人的博文,将node_modules安装的默认目录修改一下. 参考Wind ...