codeforces 804 D. Expected diameter of a tree - 分块(并不显式分块) - dp

题目大意:给你一张森林,每次询问两颗树 T A , T B ( A B ) ,求:
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 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)));
    }
}

猜你喜欢

转载自blog.csdn.net/mys_c_k/article/details/80800326