CF804D Expected diameter of a tree 樹的直徑 根號分治
阿新 • • 發佈:2020-07-21
LINK:Expected diameter of a tree
1e5 帶根號log 竟然能跑過!
容易想到每次連線兩個聯通快 快速求出直徑 其實是 \(max(D1,D2,f_x+f_y+1)\) 其中\(D1,D2\)分別為兩個聯通塊內的直徑.
\(f_x\)表示 從x出發的最長鏈.
這樣容易想到 列舉一個塊的點 然後其實要找到 \(C=max(D1,D2)\) 第一個位置滿足\(>C-f_x-1\) 然後就能統計答案了.
排序後掃描 複雜度要高 不如排序後二分.
然後加一個記憶化就過了.
原因是 這樣其實本質上是一個根號分治.
對於每次詢問的兩個塊\(x,y\)如果有一個塊小於\(\sqrt n\)
如果兩個塊同時大於\(\sqrt n\) 那麼顯然對於每個大於\(\sqrt n\)的集合都有\(\sqrt n\)次這樣的詢問.
求和可以得到複雜度還是為\(n\sqrt n \cdot logn\) 至此可以通過此題.
code
//#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<ctime> #include<cctype> #include<queue> #include<deque> #include<stack> #include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<string> #include<ctime> #include<cmath> #include<cctype> #include<cstdlib> #include<queue> #include<deque> #include<stack> #include<vector> #include<algorithm> #include<utility> #include<bitset> #include<set> #include<map> #define ll long long #define db double #define INF 1000000001 #define ldb long double #define pb push_back #define put_(x) printf("%d ",x); #define get(x) x=read() #define gt(x) scanf("%d",&x) #define gi(x) scanf("%lf",&x) #define put(x) printf("%d\n",x) #define putl(x) printf("%lld\n",x) #define rep(p,n,i) for(RE int i=p;i<=n;++i) #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]]) #define fep(n,p,i) for(RE int i=n;i>=p;--i) #define vep(p,n,i) for(RE int i=p;i<n;++i) #define pii pair<int,int> #define mk make_pair #define RE register #define P 1000000007ll #define gf(x) scanf("%lf",&x) #define pf(x) ((x)*(x)) #define uint unsigned long long #define ui unsigned #define EPS 1e-4 #define sq sqrt #define S second #define F first using namespace std; char *fs,*ft,buf[1<<15]; inline char gc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { RE int x=0,f=1;RE char ch=gc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();} return x*f; } const int MAXN=100010; int n,m,Q,cnt,top,mx; vector<ll>G[MAXN],c[MAXN]; int g[MAXN],f[MAXN],w[MAXN],s[MAXN],id[MAXN],vis[MAXN]; int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],len; map<int,ll>H[MAXN]; inline void add(int x,int y) { ver[++len]=y;nex[len]=lin[x];lin[x]=len; ver[++len]=x;nex[len]=lin[y];lin[y]=len; } inline void dfs(int x,int fa) { vis[x]=cnt; go(x)if(tn!=fa) { dfs(tn,x); mx=max(mx,f[x]+f[tn]+1); if(f[tn]+1>f[x]) { g[x]=f[x]; f[x]=f[tn]+1; id[x]=tn; } else g[x]=max(g[x],f[tn]+1); } } inline void dp(int x,int fa) { s[++top]=f[x]; go(x)if(tn!=fa) { if(id[x]!=tn) { if(f[x]+1>f[tn]) { g[tn]=f[tn]; f[tn]=f[x]+1; id[tn]=x; } else g[tn]=max(g[tn],f[x]+1); } else { if(g[x]+1>f[tn]) { g[tn]=f[tn]; f[tn]=g[x]+1; id[tn]=x; } else g[tn]=max(g[tn],g[x]+1); } dp(tn,x); } } inline int find(int x,int y) { int l=0,r=G[x].size()-1; while(l+1<r) { int mid=(l+r)>>1; if(c[x][mid]<=y)l=mid; else r=mid; } if(c[x][r]<=y)return r; return l; } inline ll calc(int x,int y) { if(H[x].find(y)!=H[x].end())return H[x][y]; int cc=max(w[x],w[y]); ll ans=0; vep(0,G[x].size(),i) { if(c[y][0]>cc-c[x][i]-1) { ans+=(ll)(1+c[x][i])*G[y].size()+G[y][G[y].size()-1]; continue; } if(c[y][c[y].size()-1]<=cc-c[x][i]-1) { ans+=(ll)G[y].size()*cc; continue; } int ww=find(y,cc-c[x][i]-1); ans+=(ll)(ww+1)*cc+G[y][G[y].size()-1]-G[y][ww]+(1+c[x][i])*(G[y].size()-ww-1); } H[x][y]=ans;return ans; } int main() { //freopen("1.in","r",stdin); get(n);get(m);get(Q); rep(1,m,i)add(read(),read()); rep(1,n,i) { if(vis[i])continue; mx=top=0;++cnt;dfs(i,0);dp(i,0); sort(s+1,s+1+top);w[cnt]=mx; rep(1,top,j)G[cnt].pb(s[j]),c[cnt].pb(s[j]); rep(1,top-1,j)G[cnt][j]+=G[cnt][j-1]; } rep(1,Q,i) { int get(x),get(y); if(vis[x]==vis[y]){puts("-1");continue;} x=vis[x];y=vis[y]; if(G[x].size()>G[y].size())swap(x,y); if(G[x].size()==G[y].size()&&x>y)swap(x,y); printf("%.7lf\n",1.0*calc(x,y)/(G[x].size()*G[y].size())); } return 0; }