Codeforces 804D
来源:互联网 发布:mac 微软雅黑字体关了 编辑:程序博客网 时间:2024/05/29 14:41
首先对于每棵树求出从每个点出发最长路径的长度(他们中最大值为直径)
从小到大排序,并记录前缀和。一开始我以为处理询问时有厉害的做法,但事实上就是利用启发式的思想,挑选点较小的那一棵树,然后枚举所有的点,由于答案是max(f1+f2+1,max(d1,d2)),所以我们要在另一颗树中二分答案,找到大于max(d1,d2)的位置,再根据前缀和计算答案。每次处理询问时用map保存下结果,这样复杂度就得到了保证。
计算最长路径那个部分需要用到两次dfs,第一次直接记录它往下走的最长长度,第二次dfs相当于换根,把它调整为根计算答案,dfs完后还要调整回来,这也是换根的树形dp中常见的做法
include<bits/stdc++.h>#define ll long long#define ld doubleusing namespace std;const int maxn=100000+10;int rt[maxn],n,m,q,down[maxn],sz[maxn],d[maxn],zj[maxn],cnt;vector<int> g[maxn];vector<int> h[maxn];vector<ll> sum[maxn];map<int,ld> mp[maxn];void dfs1(int p,int fa){ sz[rt[p]]++; for(int i=0;i<g[p].size();i++) { int v=g[p][i];if(v==fa) continue; rt[v]=rt[p];dfs1(v,p); down[p]=max(down[p],down[v]+1); }}void dfs2(int p,int fa){ int mx1=-1,mx2=-1;d[p]=down[p]; for(int i=0;i<g[p].size();i++) { int v=g[p][i]; if(down[v]>mx1) { mx2=mx1; mx1=down[v]; } else if(down[v]>mx2) mx2=down[v]; } for(int i=0;i<g[p].size();i++) { int v=g[p][i],val=down[p],v2=down[v];if(v==fa) continue; if(down[v]==mx1) down[p]=mx2+1; else down[p]=mx1+1; down[v]=max(down[v],down[p]+1); dfs2(v,p); down[p]=val; down[v]=v2; }}int main(){ //freopen("test.in","r",stdin); scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=m;i++) { int x,y;scanf("%d%d",&x,&y); g[x].push_back(y); g[y].push_back(x); } for(int i=1;i<=n;i++) if(!rt[i]) { rt[i]=++cnt; dfs1(i,0); dfs2(i,0); } for(int i=1;i<=n;i++) { zj[rt[i]]=max(zj[rt[i]],d[i]); h[rt[i]].push_back(d[i]); } for(int i=1;i<=cnt;i++) { sort(h[i].begin(),h[i].end()); sum[i].push_back(h[i][0]); for(int j=1;j<h[i].size();j++) sum[i].push_back(sum[i][j-1]+h[i][j]); } for(int i=1;i<=q;i++) { int x,y,u,v;scanf("%d%d",&x,&y); u=rt[x];v=rt[y]; if(u==v) puts("-1"); else { if(sz[u]>sz[v]||(sz[u]==sz[v]&&u>v)) swap(u,v); if(mp[u].count(v)) printf("%.9lf\n",mp[u][v]); else { int maxx=max(zj[u],zj[v]);ll res=0; for(int j=0;j<h[u].size();j++) { int p=h[u][j]; if(h[v][sz[v]-1]+p+1<=maxx) res+=(ll)sz[v]*maxx; else { int nx=upper_bound(h[v].begin(),h[v].end(),maxx-1-p)-h[v].begin(); res+=(ll)nx*maxx+(ll)(sz[v]-nx)*(p+1); res+=sum[v][sz[v]-1]; if(nx) res-=sum[v][nx-1]; } } ld out=(ld)res/((ld)sz[u]*sz[v]); printf("%.9lf\n",out); mp[u][v]=out; } } } return 0;}
0 0
- Codeforces 804D
- 【Codeforces Round #411 (Div. 1)】Codeforces 804D
- CodeForces 617D CodeForces 617D
- CodeForces 101D
- CodeForces 103D
- CodeForces 222D Olympiad
- codeforces 242d
- CodeForces 111D
- 【codeforces】3D
- CodeForces 127D Password
- codeforces 257D. Sum
- Codeforces 292D
- Codeforces 275D
- Codeforces 126D
- Codeforces 337d
- Codeforces D. Points
- codeforces 96D Volleyball
- Codeforces 165D
- 树莓派Ubuntu Mate系统中开启ssh
- 用链表解决淘汰出局问题(c++)
- ORACE 非归档模式redo文件恢复
- 广度搜索加奇偶剪枝
- Java入门学习-深入理解集合
- Codeforces 804D
- shell连接linux失败问题
- Jersey2xjersey-media-multipart+Jetty实现文件上传下载
- HTML5实现音频和视频嵌入
- 【多线程研究专题三】【FutureTask与Callable的本质】
- Linux常用命令(2)(欢迎指正,持续更新)
- Predict the Winner
- 日期格式DateFormat使用
- sed命令入门及进阶