卢总教我们的big-small思想,神奇的一匹。也就是分块的思想。
首先一手树形DP吧每个树的的每个点的最远长度预处理出来。对于两棵树,每一对点u,v只有两种情况,maxlen=max(maxlenu,maxlenv),一种是u的最远路+v的最远路+1>maxlen,另一钟相反。于是我们只要枚举一棵树中的点,然后对另一棵树中的点进行二分处理,前缀和优化一下,两种情况就可以logn求和了了,所以 查询2棵树的复杂度是min(sizeu,sizev)*log(max(sizeu,sizev))。然而直接去暴力还是有可能超时的,比如u和v都是n/2,查询q次,瞬间tle。
topline=根号n,对于大于topline的树最多有根号n个,吧这些树两两预处理,最大复杂度是n^1.5*log(n^0.5)。
对于小于根号n的,则最多,根号n*log(n)*q。
网上还有做法是每次查询树x和y后就用map记录ans[x][y],然后下次再查到就直接输出。很有道理的样子,貌似卡不了。
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<map>
#define maxl 100010
using namespace std;
int n,m,q,cnt,tot,topline;
long long size[maxl],f[maxl],ehead[maxl],maxlen[maxl];
struct ed
{
int to,nxt;
}e[maxl<<1];
struct node
{
long long maxfur,maxind,secfur,secind;
}a[maxl];
vector <long long> aa[maxl],aafur[maxl],fursum[maxl];
vector <int> bigaa;
map <int,double> preans[maxl];
bool vis[maxl];
void dfs(int u,int k)
{
int v;
aa[k].push_back(u);
vis[u]=true;size[k]++;f[u]=k;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(!vis[v])
{
dfs(v,k);
if(a[v].maxfur+1>a[u].maxfur)
{
a[u].secfur=a[u].maxfur;a[u].secind=a[u].maxind;
a[u].maxfur=a[v].maxfur+1;a[u].maxind=v;
}
else if(a[v].maxfur+1>a[u].secfur)
a[u].secfur=a[v].maxfur+1,a[u].secind=v;
}
}
}
void dfs2(int u,int fa)
{
int v;vis[u]=true;
if(a[fa].maxind!=u && fa)
{
if(a[fa].maxfur+1>a[u].maxfur)
{
a[u].secfur=a[u].maxfur;a[u].secind=a[u].maxind;
a[u].maxfur=a[fa].maxfur+1;a[u].maxind=fa;
}
else if(a[fa].maxfur+1>a[u].secfur)
a[u].secfur=a[fa].maxfur+1,a[u].secind=fa;
}
if(a[fa].secind!=u && fa)
{
if(a[fa].secfur+1>a[u].maxfur)
{
a[u].secfur=a[u].maxfur;a[u].secind=a[u].maxind;
a[u].maxfur=a[fa].secfur+1;a[u].maxind=fa;
}
else if(a[fa].secfur+1>a[u].secfur)
a[u].secfur=a[fa].secfur+1,a[u].secind=fa;
}
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(!vis[v])
dfs2(v,u);
}
}
void prework()
{
memset(a,0,sizeof(a));
memset(ehead,0,sizeof(ehead));
for(int i=1;i<=tot;i++)
aa[i].clear(),aafur[i].clear(),preans[i].clear(),
fursum[i].clear();
cnt=0;tot=0;
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
e[++cnt].to=u;e[cnt].nxt=ehead[v];ehead[v]=cnt;
}
for(int i=1;i<=n;i++)
f[i]=i;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
if(!vis[i])
dfs(i,++tot);
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
if(!vis[i])
dfs2(i,0);
topline=ceil(sqrt(n*1.0));
for(int i=1;i<=tot;i++)
if(size[i]>=topline)
bigaa.push_back(i);
int l;
for(int i=1;i<=tot;i++)
{
l=aa[i].size();
for(int j=0;j<l;j++)
aafur[i].push_back(a[aa[i][j]].maxfur);
}
for(int i=1;i<=tot;i++)
sort(aafur[i].begin(),aafur[i].end()),maxlen[i]=aafur[i][size[i]-1];
for(int i=1;i<=tot;i++)
{
l=aa[i].size();
fursum[i].push_back(aafur[i][0]);
for(int j=1;j<l;j++)
fursum[i].push_back(fursum[i][j-1]+aafur[i][j]);
}
}
void getpreans()
{
int l=bigaa.size(),u,v,lu,lv,x,left,right;
long long sum;
double ans;
for(int i=0;i<l;i++)
for(int j=i+1;j<l;j++)
{
sum=0;
u=bigaa[i];v=bigaa[j];
if(size[u]>size[v])
swap(u,v);
lu=aa[u].size();lv=aa[v].size();
for(int ii=0;ii<lu;ii++)
{
x=aa[u][ii];
left=lower_bound(aafur[v].begin(),aafur[v].end(),
max(maxlen[u],maxlen[v])-a[x].maxfur)-
aafur[v].begin();
if(left-1<0)
sum+=fursum[v][lv-1]+(lv-left)*(a[x].maxfur+1);
else
sum+=fursum[v][lv-1]-fursum[v][left-1]+(lv-left)*(a[x].maxfur+1);
sum+=(left-1+1)*max(maxlen[u],maxlen[v]);
}
ans=(double)sum/((double)size[u]*size[v]);
preans[u][v]=ans;preans[v][u]=ans;
}
}
void mainwork()
{
int u,v,lu,lv,x,left,right;
long long sum;
double ans;
getpreans();
for(int i=1;i<=q;i++)
{
scanf("%d%d",&u,&v);
u=f[u];v=f[v];
if(u==v)
printf("-1\n");
else
if(size[u]>=topline && size[v]>=topline)
printf("%.10f\n",preans[u][v]);
else
{
sum=0;
if(size[u]>size[v])
swap(u,v);
lu=aa[u].size();lv=aa[v].size();
for(int ii=0;ii<lu;ii++)
{
x=aa[u][ii];
left=lower_bound(aafur[v].begin(),aafur[v].end(),
max(maxlen[u],maxlen[v])-a[x].maxfur)-
aafur[v].begin();
if(left-1<0)
sum+=fursum[v][lv-1]+(lv-left)*(a[x].maxfur+1);
else
sum+=fursum[v][lv-1]-fursum[v][left-1]+(lv-left)*(a[x].maxfur+1);
sum+=(left-1+1)*max(maxlen[u],maxlen[v]);
}
ans=(double)sum/((double)size[u]*size[v]);
printf("%.10f\n",ans);
}
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&q))
{
prework();
mainwork();
}
return 0;
}