GDOI【JZOJ4794】富爷说是一棵树
来源:互联网 发布:vb自动更新登陆器源码 编辑:程序博客网 时间:2024/05/20 03:39
Description
富爷说来一棵树,于是大头栽了一棵树。树大了,有n个点和n - 1条边,任意两个点都是联通的,点的标号为1 - n。爱树的大头和富爷在树上安居乐业,但大头住在u,而富爷住在v,他们都很不高兴,因为u到v有且只有一条简单路径。
当然了,树王富爷找到了解决办法,他打算带着大头再给树建一条边(保证不是自环),而且他们会在n * (n - 1) / 2的方案中随机选择一种。
但,要让富爷和大头开心是有条件的。只有新建边之后,富爷去大头家以及大头去富爷家存在两条路径不会走相同的边时,他们才会呵呵(也就是说 存在一个简单环包含u和v)。
不开心的事情选择忘记。当富爷和大头开心时,你能得到愉快值等于环的大小。所以,你要告诉富爷和大头,当他们开心时(只考虑在环内),他们的期望愉悦值。
Data Constraint
20% n,m <= 2000
40% n,m <= 10^5 树是随机的
60% n,m <= 10^5 每个点的度数均为2
100% n,m <= 10^5
Solution
这种题一看就知道是用lca搞最近公共祖先。我们对情况分一下类:
1、当询问x,y不是祖先关系时(即x不是y的儿子或y不是x的儿子),我们只需将双方的子树的大小分别乘上对方子树所有点到该子树顶点的距离,相加再除以情况数即可。式子为ans=(size[x]*g[y]+size[y] *g[x])/(size[x] *size[y])(g[i]表示以i为根的子树所有点到该子树顶点i的距离)
2、当询问x,y是祖先关系时,这时我们就要考虑,设k是y的直接儿子且k是x的祖先。这时的连边情况的两个集合显然是(1)除k的子树以外,整棵树所有点和(2)x的子树相连(为什么,你画画图就知道啦)。所以我们仿照情况1已进行计算,稍加改变即可。
代码
#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const int maxn=200005;int first[maxn],last[maxn],next[maxn],f[maxn][20];ll n,m,i,t,j,k,l,x,y,num,v[maxn],fa[maxn];ll size[maxn],g[maxn],p[maxn],deep[maxn];bool bz[maxn];double len,ans;void lian(int x,int y){ last[++num]=y;next[num]=first[x];first[x]=num;}int lca(int x,int y){ int i,j,t=0,k,l; if (deep[x]<deep[y]) swap(x,y); for (i=log(n)/log(2);i>=0;i--) if (deep[f[x][i]]>=deep[y]) len+=(1<<i),x=f[x][i]; if (x==y) return x; for (i=log(n)/log(2);i>=0;i--) if (f[x][i]!=f[y][i]) len+=2*(1<<i),x=f[x][i],y=f[y][i]; len+=2; return f[x][0];}int main(){// freopen("data.in","r",stdin);freopen("data.uot","w",stdout); scanf("%d%d",&n,&m); for (i=1;i<n;i++) scanf("%d%d",&x,&y),lian(x,y),lian(y,x); for (i=1;i<=n;i++) size[i]=1; v[1]=1;i=0;j=1;deep[1]=1;bz[1]=true; while (i<j){ x=v[++i]; for (t=first[x];t;t=next[t]){ if (last[t]==fa[x])continue; bz[last[t]]=true; v[++j]=last[t];fa[last[t]]=x;deep[v[j]]=deep[x]+1; } } while (j) size[fa[v[j]]]+=size[v[j]],f[v[j]][0]=fa[v[j]],g[fa[v[j]]]+=g[v[j]]+size[v[j]],j--; for (i=2;i<=n;i++){ p[v[i]]=g[fa[v[i]]]-g[v[i]]+p[fa[v[i]]]+n-2*size[v[i]]; } for (j=1;j<=log(n)/log(2);j++) for (i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; for (i=1;i<=m;i++){ scanf("%d%d",&x,&y);len=0; if (deep[x]<deep[y]) swap(x,y); t=lca(x,y); if (t!=y) ans=len+(g[x]*size[y]+g[y]*size[x])*1.0/(size[x]*size[y])+1; else{ k=x; for (j=log(n)/log(2);j>=0;j--) if (deep[f[k][j]]>deep[y]) k=f[k][j]; t=g[y]+p[y]-g[k]-size[k]; l=n-size[k]; ans=g[x]*l+t*size[x]+(len+1)*(size[x]*l); ans=ans/(size[x]*l*1.0); } printf("%.8lf\n",ans); }}
3 0
- GDOI【JZOJ4794】富爷说是一棵树
- 【GDOI模拟】富爷说是一棵树
- 富爷说是一颗树
- 说是
- GDOI 总结
- GDOI总结
- GDOI 加油
- 2017 GDOI
- 2017gdoi
- 2017GDOI
- 备战GDOI
- 说是这样
- GDOI 3.21 模拟总结
- GDOI改题小结
- 【GDOI】模拟8.1总结
- 【GDOI】模拟8.2总结
- 【GDOI】模拟8.3总结
- GDOI模拟8.1
- 1加到n
- 回忆java来时路-第七章 类的初始化
- 【Dongle】【Web】JQuery总结
- android Spinner控件详解【转】
- MongoDB:The Definitive Guide 2nd笔记之system.profile
- GDOI【JZOJ4794】富爷说是一棵树
- 动漫知多少
- 唯有跑步于读书不能辜负
- ARCH-LINUX 安装后wifi 不能联网修改
- 第五周 项目1-建立顺序栈算法库
- 学习C语言入门心得笔记
- 操作系统
- ==和equals的区别
- Leetcode 220. Contains Duplicate III (Medium) (cpp)