河童重工,恐怖如斯
博客园 ver.
显然是 Boruvka,考虑一次怎么求边。
一棵树的时候是简单的,树形 dp 即可。考虑第二棵树是菊花怎么做,显然这个问题等价于完全图上的边权形如
还有一个问题就是如果每次点分治时都对原树做一遍 dp,复杂度为
代码里面有份暴力,所以看上去比较长。
洛谷 ver.
完全图最小生成树,考虑 Boruvka。
先来考虑一个弱化弱化版,只有一棵树,边权为
再来考虑一个弱化版,第二棵树是菊花应该怎么做,显然这个问题和上面那个等价,菊花图上任意两个点之间的距离就是两个点到根的距离之和,时间复杂度
回到这个问题,我们想转化到弱化版的问题,即距离可以写成两个数的和的形式,不难想到点分治,对第二棵树点分治,这样每对点之间的距离就能写成
这样的复杂度还是不对,我们每次点分治都要对第一棵树做
可以发现每轮 Boruvka 虚树形态是固定的,因此可以提前建好虚树,时间复杂度为
#include<bits/stdc++.h> namespace brute_force{ // #include<bits/stdc++.h> #define int long long #define fi first #define se second #define pii std::pair<int,int> #define vint std::vector<int> #define vpair std::vector<pii> #define debug(...) fprintf(stderr,##__VA_ARGS__) template<typename T> void read(T &x){ x=0; int f=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar(); x*=f; } std::stack<char>st; template<typename T> void print(T x){ if(x==0) putchar('0'); if(x<0) putchar('-'),x=-x; while(st.size()) st.pop(); while(x) st.push((char)('0'+x%10)),x/=10; while(st.size()) putchar(st.top()),st.pop(); } template<typename T> void printsp(T x){ print(x),putchar(' '); } template<typename T> void println(T x){ print(x),putchar('\n'); } template<typename T,typename I> bool chkmin(T &a,I b){ if(a>b) return a=b,1; return 0; } template<typename T,typename I> bool chkmax(T &a,I b){ if(a<b) return a=b,1; return 0; } template<typename T,typename I> void addedge(std::vector<I>*vec,T u,T v){ vec[u].push_back(v); } template<typename T,typename I,typename K> void addedge(std::vector<K>*vec,T u,T v,I w){ vec[u].push_back({v,w}); } template<typename T,typename I> void addd(std::vector<I>*vec,T u,T v){ addedge(vec,u,v),addedge(vec,v,u); } template<typename T,typename I,typename K> void addd(std::vector<K>*vec,T u,T v,I w){ addedge(vec,u,v,w),addedge(vec,v,u,w); } bool Mbe; const int inf=1e18,MOD1=998244353,MOD2=1e9+7; const int maxn=1e3+10; vpair a[maxn],b[maxn],c[maxn]; int n,dis1[maxn],dis2[maxn],f[maxn][20],g[maxn][20],dep1[maxn],dep2[maxn]; struct edge{ int u,v,w; }d[maxn*maxn]; namespace DSU{ int to[maxn]; void init_(){ for(int i=1;i<=n;i++) to[i]=i; } int go(int x){ if(to[x]==x) return x; return to[x]=go(to[x]); } bool merge(int x,int y){ x=go(x),y=go(y); if(x==y) return 0; to[x]=y; return 1; } } using namespace DSU; void dfs1(int p,int fa){ dep1[p]=dep1[fa]+1; f[p][0]=fa; for(pii i:a[p]){ if(i.fi==fa) continue; dis1[i.fi]=dis1[p]+i.se; dfs1(i.fi,p); } } void dfs2(int p,int fa){ dep2[p]=dep2[fa]+1; g[p][0]=fa; for(pii i:b[p]){ if(i.fi==fa) continue; dis2[i.fi]=dis2[p]+i.se; dfs2(i.fi,p); } } edge made(int u,int v,int w){ edge res; res.u=u,res.v=v,res.w=w; return res; } void init(){ for(int j=1;j<=19;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1],g[i][j]=g[g[i][j-1]][j-1]; } int lca1(int x,int y){ if(dep1[x]<dep1[y]) std::swap(x,y); for(int i=19;i>=0;i--) if(dep1[f[x][i]]>=dep1[y]) x=f[x][i]; if(x==y) return x; for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int lca2(int x,int y){ if(dep2[x]<dep2[y]) std::swap(x,y); for(int i=19;i>=0;i--) if(dep2[g[x][i]]>=dep2[y]) x=g[x][i]; if(x==y) return x; for(int i=19;i>=0;i--) if(g[x][i]!=g[y][i]) x=g[x][i],y=g[y][i]; return g[x][0]; } bool cmp(edge s1,edge s2){ return s1.w<s2.w; } bool Men; void main(){ debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0); read(n); int x,y,v; #define sb(a) read(x),read(y),read(v),addd(a,x,y,v) for(int i=1;i<n;i++) sb(a); for(int i=1;i<n;i++) sb(b); dfs1(1,0),dfs2(1,0),init(); int cnt=0; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++){ int cost=dis1[i]+dis1[j]-2*dis1[lca1(i,j)]+dis2[i]+dis2[j]-2*dis2[lca2(i,j)]; // addd(a,i,j,cost); d[++cnt].u=i,d[cnt].v=j,d[cnt].w=cost; } init_(); std::sort(d+1,d+cnt+1,cmp); int cost=0; std::vector<edge>vec; for(int i=1;i<=cnt;i++){ int u=d[i].u,v=d[i].v,w=d[i].w; if(!merge(u,v)) continue; cost+=w; vec.push_back(made(u,v,w)); // addd(c,u,v); } println(cost); for(edge i:vec) printf("%lld %lld %lld\n",i.u,i.v,i.w); // for(int i=1;i<=n;i++) // for(int j:vost) debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC); }} #define int long long #define fi first #define se second #define pii std::pair<int,int> #define vint std::vector<int> #define vpair std::vector<pii> #define debug(...) fprintf(stderr,##__VA_ARGS__) template<typename T> void read(T &x){ x=0; int f=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar(); x*=f; } std::stack<char>st; template<typename T> void print(T x){ if(x==0) putchar('0'); if(x<0) putchar('-'),x=-x; while(st.size()) st.pop(); while(x) st.push((char)('0'+x%10)),x/=10; while(st.size()) putchar(st.top()),st.pop(); } template<typename T> void printsp(T x){ print(x),putchar(' '); } template<typename T> void println(T x){ print(x),putchar('\n'); } template<typename T,typename I> bool chkmin(T &a,I b){ if(a>b) return a=b,1; return 0; } template<typename T,typename I> bool chkmax(T &a,I b){ if(a<b) return a=b,1; return 0; } template<typename T,typename I> void addedge(std::vector<I>*vec,T u,T v){ vec[u].push_back(v); } template<typename T,typename I,typename K> void addedge(std::vector<K>*vec,T u,T v,I w){ vec[u].push_back({v,w}); } template<typename T,typename I> void addd(std::vector<I>*vec,T u,T v){ addedge(vec,u,v),addedge(vec,v,u); } template<typename T,typename I,typename K> void addd(std::vector<K>*vec,T u,T v,I w){ addedge(vec,u,v,w),addedge(vec,v,u,w); } bool Mbe; const int inf=1e18,MOD1=998244353,MOD2=1e9+7; const int maxn=1e5+10; int n,num,sz[maxn],mx[maxn],dfn[maxn],edfn[maxn*2],cnt,tot,fir[maxn],fdfn[maxn],mt[maxn*2][18],lg[maxn*2],dis[maxn],bel[maxn],val[maxn],best[maxn],sec[maxn],bcol[maxn],seccol[maxn]; bool vis[maxn]; vint col[maxn],vec; vpair a[maxn],b[maxn],mst; struct edge{ int u,v,w; }; edge newedge(int u,int v,int w){ edge res; res.u=u,res.v=v,res.w=w; return res; } struct Tree{ int rt; std::vector<edge>a; }dot[maxn]; namespace LCA{ void dfs(int p,int fa){ dfn[p]=++cnt,edfn[++tot]=dfn[p]; fir[p]=tot,fdfn[cnt]=p; for(pii i:a[p]){ if(i.fi==fa) continue; dis[i.fi]=dis[p]+i.se; dfs(i.fi,p); edfn[++tot]=dfn[p]; } } void init(){ dfs(1,0); for(int i=1;i<=tot;i++) mt[i][0]=edfn[i]; for(int j=1;j<20;j++) for(int i=1;i+(1ll<<j)-1<=tot;i++) mt[i][j]=std::min(mt[i][j-1],mt[i+(1ll<<(j-1))][j-1]); lg[0]=-1; for(int i=1;i<=tot;i++) lg[i]=lg[i>>1]+1; } int query(int l,int r){ if(l>r) std::swap(l,r); int len=r-l+1; return std::min(mt[l][lg[len]],mt[r-(1ll<<lg[len])+1][lg[len]]); } int lca(int x,int y){ return fdfn[query(fir[x],fir[y])]; } } void pdfs(int p,int fa){ vec.push_back(p); sz[p]=1; mx[p]=0; for(pii i:b[p]){ if(i.fi==fa||vis[i.fi]) continue; pdfs(i.fi,p); sz[p]+=sz[i.fi]; chkmax(mx[p],sz[i.fi]); } // debug("p=%lld sz=%lld mx=%lld\n",p,sz[p],mx[p]); } int zx,siz; void findrt(int p,int fa,int gt){ // debug("p=%lld gt=%lld mx=%llld siz=%lld\n",p,gt,mx[p],siz);; if(std::max(gt,mx[p])<siz) zx=p,siz=std::max(gt,mx[p]); for(pii i:b[p]){ if(i.fi==fa||vis[i.fi]) continue; findrt(i.fi,p,gt+sz[p]-sz[i.fi]); } } bool cmp_dfn(int x,int y){ return dfn[x]<dfn[y]; } void dfs(int p){ vec.clear(); siz=inf; pdfs(p,0),findrt(p,0,0); vint nd; // debug("zx=%lld\n",zx); std::sort(vec.begin(),vec.end(),cmp_dfn); // for(int i:vec) debug("i=%lld\n",i); for(int i=1;i<vec.size();i++){ int lca=LCA::lca(vec[i],vec[i-1]); nd.push_back(lca); // debug("%lld %lld lca:%lld\n",vec[i],vec[i-1],lca); // dot[zx].a.push_back(newedge(vec[i],lca,dis[vec[i]]-dis[lca])); // debug("%lld - %lld > %lld\n",vec[i],lca,dis[vec[i]]-dis[lca]); // debug("zx=%lld %lld %lld\n",zx,vec[i]) } for(int i:nd) vec.push_back(i); std::sort(vec.begin(),vec.end(),cmp_dfn); auto z=std::unique(vec.begin(),vec.end()); auto i=vec.begin(); int las=*i; i++; for(;i!=z;i++){ int now=*i; int lca=LCA::lca(las,now); dot[zx].a.push_back(newedge(now,lca,dis[now]-dis[lca])); // debug("%lld - %lld > %lld\n",now,lca,dis[now]-dis[lca]); las=now; } int mi=inf; for(int i:vec) if(chkmin(mi,dfn[i])) dot[zx].rt=i; vis[zx]=1; for(pii i:b[zx]) if(!vis[i.fi]) dfs(i.fi); } int cost; namespace DSU{ int to[maxn]; void init(){ for(int i=1;i<=n;i++) to[i]=i; } int go(int p){ if(to[p]==p) return p; return to[p]=go(to[p]); } void merge(int x,int y){ x=go(x),y=go(y); if(x==y) return ; to[x]=y; } } int ok[maxn],tim; namespace getMST{ int sz[maxn],mx[maxn],zx,siz,cho[maxn],id[maxn]; bool vis[maxn]; vpair c[maxn]; namespace VT{ void dfs(int p,int fa){ for(pii i:c[p]){ if(i.fi==fa) continue; dfs(i.fi,p); } if(ok[p]!=tim) val[p]=inf; best[p]=val[p],bcol[p]=bel[p]; sec[p]=inf,seccol[p]=0; for(pii i:c[p]){ if(i.fi==fa) continue; if(best[i.fi]+i.se<=best[p]){ if(bcol[i.fi]==bcol[p]) best[p]=best[i.fi]+i.se; else sec[p]=best[p],seccol[p]=bcol[p],best[p]=best[i.fi]+i.se,bcol[p]=bcol[i.fi]; }else if(best[i.fi]+i.se<=sec[p]&&bcol[p]!=bcol[i.fi]){ sec[p]=best[i.fi]+i.se,seccol[p]=bcol[i.fi]; } if(sec[i.fi]+i.se<=sec[p]&&seccol[i.fi]!=bcol[p]) sec[p]=sec[i.fi]+i.se,seccol[p]=seccol[i.fi]; } // best[p]+=val[p],sec[p]+=val[p]; // debug("p=%lld best=%lld bcol=%lld sec=%lld seccol=%lld\n",p,best[p],bcol[p],sec[p],seccol[p]); } void pdfs(int p,int fa,int bst,int snd,int bstcol,int sndcol){ int w=inf; if(bel[p]!=bcol[p]) chkmin(w,best[p]); if(bstcol!=bel[p]) chkmin(w,bst); if(bel[p]!=seccol[p]) chkmin(w,sec[p]); if(bel[p]!=sndcol) chkmin(w,snd); if(chkmin(cho[bel[p]],w+val[p])){ if(w==best[p]&&bcol[p]!=bel[p]) id[bel[p]]=bcol[p]; else if(w==bst&&bstcol!=bel[p]) id[bel[p]]=bstcol; else if(w==snd&&sndcol!=bel[p]) id[bel[p]]=sndcol; else id[bel[p]]=seccol[p]; } // debug("p=%lld bst=%lld snd=%lld bstcol=%lld sndcol=%lld w=%lld cho=%lld id=%lld\n",p,bst,snd,bstcol,sndcol,w,cho[bel[p]],id[bel[p]]); int bw=std::min(std::min(std::min(bst,snd),best[p]),sec[p]),bc; int cw=inf,cc; if(bw==best[p]) bc=bcol[p]; else bc=bstcol; if(snd<cw&&sndcol!=bc) cw=snd,cc=sndcol; if(sec[p]<cw&&seccol[p]!=bc) cw=sec[p],cc=seccol[p]; // if(cw==snd) cc=sndcol; // else cc=seccol[p]; if(bw==best[p]&&bcol[p]!=bstcol&&bst<cw) cw=bst,cc=bstcol; if(bw==bst&&bstcol!=bcol[p]&&best[p]<cw) cw=best[p],cc=bcol[p]; for(pii i:c[p]){ if(i.fi==fa) continue; pdfs(i.fi,p,bw+i.se,cw+i.se,bc,cc); } } } void pdfs(int p,int fa){ sz[p]=1,mx[p]=0,ok[p]=tim; for(pii i:b[p]){ if(i.fi==fa||vis[i.fi]) continue; pdfs(i.fi,p); sz[p]+=sz[i.fi]; chkmax(mx[p],sz[i.fi]); } } void findrt(int p,int fa,int gt){ if(chkmin(siz,std::max(mx[p],gt))) zx=p; for(pii i:b[p]){ if(i.fi==fa||vis[i.fi]) continue;; findrt(i.fi,p,gt+sz[p]-sz[i.fi]); } } void getval(int p,int fa){ for(pii i:b[p]){ if(i.fi==fa||vis[i.fi]) continue; val[i.fi]=val[p]+i.se; // debug("i.fi=%lld val=%lld p=%lld i.se=%lld\n",i.fi,val[i.fi],p,i.se); getval(i.fi,p); } } void dfs(int p){ tim++; siz=inf; pdfs(p,0),findrt(p,0,0); p=zx; // debug("zx=%lld\n",zx); val[p]=0,getval(p,0); for(edge i:dot[p].a){ addd(c,i.u,i.v,i.w); } VT::dfs(dot[p].rt,0),VT::pdfs(dot[p].rt,0,inf,inf,-1,-1); for(edge i:dot[p].a) c[i.u].clear(),c[i.v].clear(); vis[zx]=1; for(pii i:b[p]){ if(vis[i.fi]) continue; dfs(i.fi); } } int to[maxn]; void Boruvka(){ // debug("ok\n"); // DSU::init(); for(int i=1;i<=n;i++) for(int j:col[i]) bel[j]=i,cho[i]=inf,id[i]=i;//,debug("i=%lld j=%lld\n",i,j); memset(vis,0,sizeof(vis)); dfs(1); for(int i=1;i<=n;i++){ if(!col[i].size()) continue; if(DSU::go(i)==DSU::go(id[i])) continue; // if(id[i]<i) continue; cost+=cho[i]; num--; DSU::merge(i,id[i]); // for(int j:col[id[i]]) col[i].push_back(j); } for(int i=1;i<=n;i++) col[i].clear(); for(int i=1;i<=n;i++) col[DSU::go(i)].push_back(i); } } bool Men; signed main(){ // freopen("data.in","r",stdin),freopen("my.out","w",stdout); // brute_force::main(); // return 0; debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0); read(n); for(int i=1;i<n;i++){ int x,y,v; read(x),read(y),read(v); addd(a,x,y,v); } LCA::init(); for(int i=1;i<n;i++){ int x,y,v; read(x),read(y),read(v); addd(b,x,y,v); } dfs(1); for(int i=1;i<=n;i++) col[i].push_back(i); num=n; DSU::init(); while(num!=1) getMST::Boruvka(); println(cost); debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC); } /* 5 2 1 12 3 1 3 4 2 6 5 4 1 2 1 9 3 2 14 4 3 4 5 3 13 5 2 1 14 3 2 6 4 1 13 5 4 14 2 1 8 3 2 4 4 3 15 5 1 7 */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】