Codeforces 804D
2017-05-07 23:35
169 查看
首先对于每棵树求出从每个点出发最长路径的长度(他们中最大值为直径)
从小到大排序,并记录前缀和。一开始我以为处理询问时有厉害的做法,但事实上就是利用启发式的思想,挑选点较小的那一棵树,然后枚举所有的点,由于答案是max(f1+f2+1,max(d1,d2)),所以我们要在另一颗树中二分答案,找到大于max(d1,d2)的位置,再根据前缀和计算答案。每次处理询问时用map保存下结果,这样复杂度就得到了保证。
计算最长路径那个部分需要用到两次dfs,第一次直接记录它往下走的最长长度,第二次dfs相当于换根,把它调整为根计算答案,dfs完后还要调整回来,这也是换根的树形dp中常见的做法
从小到大排序,并记录前缀和。一开始我以为处理询问时有厉害的做法,但事实上就是利用启发式的思想,挑选点较小的那一棵树,然后枚举所有的点,由于答案是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 double using 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; }
相关文章推荐
- 【Codeforces Round #411 (Div. 1)】Codeforces 804D
- codeforces 93 div2 D题 - kmp- 3
- 【Codeforces】 21D Traveling Graph
- codeforces 650D. Zip-line 线段树
- CodeForces 681B
- 【codeforces 782B】The Meeting Place Cannot Be Changed(二分)
- CodeForces 538B想法题
- Codeforces 908A (New Year and Counting Cards)914A(Perfect Squares)
- [刷题笔记]codeforces 44B - 通过判定减少循环层数。
- CodeForces 342B Xenia and Spies
- codeforces-1B-Spreadsheets( C++ && PHP && 字符串操作 && 数学逻辑 )
- CodeForces 681C Heap Operations
- CodeForces - 149D Coloring Brackets 详细题解(递归区间DP+dfs染色,好题)
- Codeforces 827E Rusty String - 快速傅里叶变换 - 暴力
- CodeForces 940A Points on the line
- [刷题笔记] Codeforces 115B ,一个清楚的大脑
- Codeforces 520E. Pluses everywhere 数学
- CodeForces 630K: Indivisibility【容斥】
- 【codeforces 653 A Bear and Three Balls】
- Codeforces 777A