题目大意:给你一张森林,每次询问两颗树
TA,TB(A≠B)
T
A
,
T
B
(
A
≠
B
)
,求:
∑x∈TA∑y∈TBD(T=(V(TA)⋃V(TB),E(TA)⋃E(TB)⋃{(x,y)}))
∑
x
∈
T
A
∑
y
∈
T
B
D
(
T
=
(
V
(
T
A
)
⋃
V
(
T
B
)
,
E
(
T
A
)
⋃
E
(
T
B
)
⋃
{
(
x
,
y
)
}
)
)
其中D(T)表示树T的直径。如果A=B输出-1。
题解:考虑暴力,记D(T)表示树T的直径,d(x)表示从x出发的最长链,那么答案就是:
∑x∈TA,y∈TBmax(d(x)+d(y)+1,max(D(TA),D(TB)))
∑
x
∈
T
A
,
y
∈
T
B
m
a
x
(
d
(
x
)
+
d
(
y
)
+
1
,
m
a
x
(
D
(
T
A
)
,
D
(
T
B
)
)
)
然后令T=max(DA,DB),那么就是问,da+db+1<=T的a,b有多少对,以及da+db+1>T的da+db+1的和。那么我们与处理d的排序显然每次询问就可以扫描一个在另一个二分在O(min(szA,szB)lg)时间内出解(注意这里特意不用双指针做到szA+szB)。那么考虑按照sz大小分块,块大小s,如果min(szA,szB)<=s那么就O(slgs)暴力,否则只有n^2/s^2对树,每一对都双指针就可以在总n^2/s的时间内预处理(就是每一棵树对时间复杂度的贡献都是sz*(n/s),然后sigma sz=n)。如果认为q和n同阶那么s^2lgs=n,最后复杂度nsqrt(n)lgn。
略微有些不好写,注意到预处理是不需要的,因为预处理的目的就是避免多次询问用一个问题,那么可以到了询问的时候检查一下是否是第一次询问,是的话就计算,不是的话就直接输出。这样发现就不用人为的去分块了,天然已经分块好了,复杂度不变但是好写很多。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<unordered_map>
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
#define lint long long
#define db long double
#define hv(x,y) ((lint)x*n+y)
#define N 100010
using namespace std;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct edges{
int to,pre;
}e[N<<1];int h[N],etop,l[N][2],ms[N],T[N],bel[N];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
unordered_map<lint,db> Ans;
vector<int> d[N];vector<lint> s[N];
inline int get_pos(vector<int> &v,int s)
{
int L=0,R=(int)v.size()-1,mid=(L+R)>>1;
while(L<=R)
{
if(v[mid]<=s) L=mid+1;
else R=mid-1;mid=(L+R)>>1;
}
return R;
}
inline db calc(int x,int y,int T,lint ans=0ll)
{
int s1=(int)d[x].size(),s2=(int)d[y].size();
lint v=s[y][s[y].size()-1];
// for(int i=0;i<(int)d[x].size();i++) cerr<<d[x][i]sp;cerr ln;
// for(int i=0;i<(int)d[y].size();i++) cerr<<d[y][i]sp;cerr ln;
for(int i=0,p;i<(int)d[x].size();i++)
p=get_pos(d[y],T-1-d[x][i]),ans+=(p+1ll)*T+(d[x][i]+1ll)*(s2-p-1ll)+v-(p>=0?s[y][p]:0);
return (db)ans/s1/s2;
}
int fir_dfs(int x,int fa,int c,int &T)
{
for(int i=h[x],y;i;i=e[i].pre)
if((y=e[i].to)^fa)
{
fir_dfs(y,x,c,T);int v=l[y][0]+1;
if(v>l[x][0]) l[x][1]=l[x][0],l[x][0]=v,ms[x]=y;
else l[x][1]=max(l[x][1],v);
}
return bel[x]=c,T=max(T,l[x][0]+l[x][1]);
}
int sec_dfs(int x,int fa,int v,vector<int> &d)
{
d.push_back(max(v,l[x][0]));
for(int i=h[x],y;i;i=e[i].pre)
if((y=e[i].to)^fa) sec_dfs(y,x,max(v,l[x][y==ms[x]])+1,d);
return 0;
}
int main()
{
int n=inn(),m=inn(),q=inn(),c=0;
for(int i=1,x,y;i<=m;i++)
x=inn(),y=inn(),add_edge(x,y),add_edge(y,x);
for(int i=1;i<=n;i++)
if(!bel[i]) c++,fir_dfs(i,0,c,T[c]),sec_dfs(i,0,0,d[c]);
for(int i=1;i<=c;i++)
{
sort(d[i].begin(),d[i].end()),s[i].push_back(d[i][0]);
for(int j=1;j<(int)d[i].size();j++) s[i].push_back(s[i][j-1]+d[i][j]);
}
while(q--)
{
int x=bel[inn()],y=bel[inn()],D=max(T[x],T[y]);
if(x==y) { printf("-1\n");continue; }
if(d[x].size()>d[y].size()) swap(x,y);
if(Ans[hv(x,y)]) printf("%.8f\n",(double)Ans[hv(x,y)]);
else printf("%.8f\n",(double)(Ans[hv(x,y)]=Ans[hv(y,x)]=calc(x,y,D)));
}
}