河童重工,恐怖如斯


博客园 ver.

显然是 Boruvka,考虑一次怎么求边。

一棵树的时候是简单的,树形 dp 即可。考虑第二棵树是菊花怎么做,显然这个问题等价于完全图上的边权形如 D(x,y)+ax+ay,这也是简单的,推广这个做法,对第二棵树点分治,每次对不同子树中的点统计贡献,这样每个点就有了两个属性(原图上的颜色、第二棵树上所在的子树),不妨分别记为 colibeli,那我们就是要找两个 belibeljcolicolj 的点。多记一下状态大力分类讨论转移可以解决。考虑是否真要这么麻烦呢?如果我们不区分 beli,考虑两个点 (i,j),他们可能会在点分治时产生贡献,但一定不是最优,考虑两者在不同子树一定比当前优,因此无需考虑区分 beli

还有一个问题就是如果每次点分治时都对原树做一遍 dp,复杂度为 O(n2)。考虑点分治时只会有 O(nlogn) 个点有用,因此只需对其建虚树即可,可以做到 O(nlog3n),由于每次做 Boruvka 的时候虚树形态相同,因此可以提前预处理出来。时间复杂度 O(nlog2n)

代码里面有份暴力,所以看上去比较长。


洛谷 ver.

完全图最小生成树,考虑 Boruvka。

先来考虑一个弱化弱化版,只有一棵树,边权为 ax+ay+dis(x,y) 应该怎么做,每轮做树形 dp,维护子树内最大值和颜色不同的次大值,时间复杂度 O(nlogn)

再来考虑一个弱化版,第二棵树是菊花应该怎么做,显然这个问题和上面那个等价,菊花图上任意两个点之间的距离就是两个点到根的距离之和,时间复杂度 O(nlogn)

回到这个问题,我们想转化到弱化版的问题,即距离可以写成两个数的和的形式,不难想到点分治,对第二棵树点分治,这样每对点之间的距离就能写成 ax+ay 的形式,然后做弱化弱化版的树形 dp 即可。注意此处的限制是要求两个点在之前的 Boruvka 中不在同一个连通块内,同时点分治不在不同一个子树中,看上去 dp 的时候要记的状态比较多,不过没有必要记是否在同一个子树中,这样显然不会最优。

这样的复杂度还是不对,我们每次点分治都要对第一棵树做 O(n) 的树形 dp,很糟糕,点分治这一算法能优化复杂度的主要地方在于点的总数是 O(nlogn) 的,启发我们建出虚树,然后在虚树上 dp。时间复杂度 O(nlog3n),三个 log 分别来自 Boruvka、点分治、建虚树。

可以发现每轮 Boruvka 虚树形态是固定的,因此可以提前建好虚树,时间复杂度为 O(nlog2n)


#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
*/
posted @   BYR_KKK  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示