日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AT3611-Tree MST【点分治,最小生成树】

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AT3611-Tree MST【点分治,最小生成树】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/AT3611


題目大意

給出nnn個點的一棵樹。

現在有一張完全圖,兩個點之間的邊權為wx+wy+dis(x,y)w_x+w_y+dis(x,y)wx?+wy?+dis(x,y)disdisdis表示樹上距離)

求這張完全圖的最小生成樹。

2≤n≤2×105,1≤wi,ci≤1092\leq n\leq 2\times 10^5,1\leq w_i,c_i\leq 10^92n2×105,1wi?,ci?109


解題思路

考慮可能作為最小生成樹的邊。

一個結論就是對于一個子圖。不在最小生成森林上的邊一定不在原圖的最小生成樹上。

這樣可以考慮分治,點分治之后對于根節點xxx,其他的節點定義fx=depx+wxf_x=dep_x+w_xfx?=depx?+wx?,那么兩個點之間邊權就是fx+fyf_x+f_yfx?+fy?了(x,yx,yx,y屬于不同子樹),對于同一子樹的我們也加進去,因為這是不優的邊所以不會影響答案。

此時圖中的最小生成森林是其他所有點連接fff值最小的點。

這樣我們可以處理出nlog?nn\log nnlogn條可能的邊,在這些邊上再跑一次最小生成樹就好了。

時間復雜度O(nlog?2n)O(n\log^2 n)O(nlog2n)


code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=2e5+10,inf=1e18; struct node{ll to,next,w; }a[N<<1]; struct edge{ll x,y,w; }e[N<<5]; ll n,tot,mins,root,ans,num,ent; ll ls[N],f[N],siz[N],w[N],fa[N]; bool v[N]; void addl(ll x,ll y,ll w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;return; } void groot(ll x,ll fa){siz[x]=1;f[x]=0;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa||v[y])continue;groot(y,x);siz[x]+=siz[y];f[x]=max(f[x],siz[y]);}f[x]=max(f[x],num-siz[x]);if(f[x]<f[root])root=x;return; } void calc(ll x,ll fa,ll dep){f[x]=w[x]+dep;if(f[x]<f[mins])mins=x;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa||v[y])continue;calc(y,x,dep+a[i].w);}return; } void adde(ll x,ll fa){e[++ent]=(edge){x,mins,f[x]+f[mins]};for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa||v[y])continue;adde(y,x);} } void solve(ll x){v[x]=1;f[x]=w[mins=x];for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(v[y])continue;calc(y,x,a[i].w);}e[++ent]=(edge){x,mins,f[x]+f[mins]};for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(v[y])continue;adde(y,x);}ll sum=num;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(v[y])continue;num=(siz[y]>siz[x])?(sum-siz[x]):siz[y];root=0;groot(y,x);solve(root);}return; } bool cmp(edge x,edge y) {return x.w<y.w;} ll find(ll x) {return (fa[x]==x)?x:(fa[x]=find(fa[x]));} signed main() {scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld",&w[i]),fa[i]=i;for(ll i=1;i<n;i++){ll x,y,w;scanf("%lld%lld%lld",&x,&y,&w);addl(x,y,w);addl(y,x,w);}num=n;f[0]=inf;groot(1,1);solve(root);sort(e+1,e+1+ent,cmp);for(ll i=1;i<=ent;i++){ll x=e[i].x,y=e[i].y;x=find(x);y=find(y);if(x!=y)ans+=e[i].w,fa[y]=x;}printf("%lld\n",ans);return 0; }

總結

以上是生活随笔為你收集整理的AT3611-Tree MST【点分治,最小生成树】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。