博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BeiJing2010组队]次小生成树Tree
阅读量:4363 次
发布时间:2019-06-07

本文共 7375 字,大约阅读时间需要 24 分钟。

Time Limit: 10 Sec Memory Limit: 512 MB

Description

小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) img 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

Input

第一行包含两个整数\(N\)\(M\),表示无向图的点数与边数。 接下来 \(M\)行,每行 \(3\)个数\(x\ \ y\ \ z\) 表示,点 \(x\) 和点\(y\)之间有一条边,边的权值为\(z\)

Output

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

Sample Input

5 6 1 2 1 1 3 2 2 4 3 3 5 4 3 4 3 4 5 6

Sample Output

11

HINT

数据中无向图无自环;

\(50\%\) 的数据\(N \leq 2 000\) \(M \leq 3 000\)

\(80\%\) 的数据\(N \leq 50000\) \(M \leq 100000\)

\(100\%\)的数据\(N \leq 100000\) \(M \leq 300000\) ,边权值非负且不超过 \(10^9\)

Solution

首先有一个结论,次小生成树与最小生成树一定只相差一条边。自己大概想象一下,如果相差多余一条边的话,那么要么那个最小生成树不是最小的,要么次小生成树不是次小的,我们都可以拿多出来的两条边和原来的树里面的边拼拼凑凑得到一个更优的最小或者次小生成树。

所以我们只需要枚举是哪一条边即可。然后,我们如果加入这条边,使得变化量最小。我们加入这条边以后,一定会与树里面原来的边形成一个环,为了让变化量最小,我们只需要抛弃掉除了这条边以外的最长的边。但是有一个问题,题目要的是严格次小生成树,所以如果这条边与原来环里面的边边权最大值想等的话,我们只能抛弃次大值了。而这个最大值的维护则是树上做LCA的套路了,次大值就跟着一起慢慢维护吧,这里可能比较繁琐。

这道题写的时候可能要想一想如何更新次大值,比较细节化。嗯不过今天写的时候可能rp好了一点,尽然过了样例以后交上去一遍A掉。

#include
#include
#include
#include
using namespace std;#define lowbit(x) ((x)&(-(x)))#define REP(i,a,n) for(register int i=(a);i<=(n);++i)#define PER(i,a,n) for(register int i=(a);i>=(n);--i)#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)#define dbg(...) fprintf(stderr,__VA_ARGS__)#define lc o<<1#define rc o<<1|1namespace io{ const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr; #define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++) inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;} inline void putc(char x){*oS++=x;if(oS==oT)flush();} template
inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;} template
inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);} struct Flusher_{~Flusher_(){flush();}}io_flusher_;}//orz laofudasuanusing io::read;using io::putc;using io::write;typedef long long ll;typedef unsigned long long ull;template
inline bool SMAX(A&x,const B&y){return x
inline bool SMIN(A&x,const B&y){return y
s[f[x][i-1]][i-1]){ s[x][i]=s[x][i-1]; if(s2[x][i-1]>s[f[x][i-1]][i-1])s2[x][i]=s2[x][i-1]; else s2[x][i]=s[f[x][i-1]][i-1]; } else if(s[x][i-1]
s[x][i-1])s2[x][i]=s2[f[x][i-1]][i-1]; else s2[x][i]=s[x][i-1]; } else s[x][i]=s[x][i-1],s2[x][i]=max(s2[x][i],s2[f[x][i-1]][i]); } for(register int i=head[x];i;i=g[i].ne)if(g[i].to!=fa)s[g[i].to][0]=g[i].w,DFS(g[i].to,x);}struct Pair{int x,y;};inline Pair LCA(int x,int y){ if(dep[x]
=0;--i)if(dep[f[x][i]]>=dep[y]){ if(s[x][i]>ans){if(s2[x][i]>ans)ans=s[x][i],ans2=s2[x][i];else ans2=ans,ans=s[x][i];} else if(s[x][i]<=ans){if(s[x][i]>ans2)ans2=s[x][i];} x=f[x][i]; } if(x==y)return Pair{ans,ans2}; for(register int i=LOG-1;i>=0;--i)if(f[x][i]!=f[y][i]){ if(s[x][i]>ans){if(s2[x][i]>ans)ans=s[x][i],ans2=s2[x][i];else ans2=ans,ans=s[x][i];} else if(s[x][i]<=ans){if(s[x][i]>ans2)ans2=s[x][i];} if(s[y][i]>ans){if(s2[y][i]>ans)ans=s[y][i],ans2=s2[y][i];else ans2=ans,ans=s[y][i];} else if(s[y][i]<=ans){if(s[y][i]>ans2)ans2=s[y][i];} x=f[x][i];y=f[y][i]; } if(s[x][0]>ans){if(s2[x][0]>ans)ans=s[x][0],ans2=s2[x][0];else ans2=ans,ans=s[x][0];} else if(s[x][0]<=ans){if(s[x][0]>ans2)ans2=s[x][0];} if(s[y][0]>ans){if(s2[y][0]>ans)ans=s[y][0],ans2=s2[y][0];else ans2=ans,ans=s[y][0];} else if(s[y][0]<=ans){if(s[y][0]>ans2)ans2=s[y][0];} x=f[x][0];y=f[y][0];return Pair{ans,ans2};}int main(){#ifndef ONLINE_JUDGE freopen("BZOJ1977.in","r",stdin);freopen("BZOJ1977.out","w",stdout);#endif read(n),read(m); for(register int i=1;i<=m;++i)read(G[i].x),read(G[i].y),read(G[i].z); Kruskal();DFS(1); for(register int i=1;i<=m;++i)if(!intr[i]){ x=G[i].x,y=G[i].y,z=G[i].z; Pair p=LCA(x,y); if(z>p.x)SMIN(ans,sum-p.x+z); else if(z==p.x&&z>p.y)SMIN(ans,sum-p.y+z); } write(ans);putc('\n');}

Update:又被人叉WA掉了,上面那个程序有一个细节没处理好,还有一处小错误,下面是修改后的代码,却不知道为什么突然变慢了。目前测过的几个OJ(BZOJ,LOJ,洛谷)数据都太弱了,大家可以试一下这组数据:

7 73 5 44 6 41 2 51 3 52 4 55 7 56 7 5

正确答案是29

#include
#include
#include
#include
using namespace std;#define lowbit(x) ((x)&(-(x)))#define REP(i,a,n) for(register int i=(a);i<=(n);++i)#define PER(i,a,n) for(register int i=(a);i>=(n);--i)#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)#define dbg(...) fprintf(stderr,__VA_ARGS__)#define lc o<<1#define rc o<<1|1namespace io{ const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr; #define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++) inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;} inline void putc(char x){*oS++=x;if(oS==oT)flush();} template
inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;} template
inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);} struct Flusher_{~Flusher_(){flush();}}io_flusher_;}//orz laofudasuanusing io::read;using io::putc;using io::write;typedef long long ll;typedef unsigned long long ull;template
inline bool SMAX(A&x,const B&y){return x
inline bool SMIN(A&x,const B&y){return y
s[f[x][i-1]][i-1]){ s[x][i]=s[x][i-1]; if(s2[x][i-1]>s[f[x][i-1]][i-1])s2[x][i]=s2[x][i-1]; else s2[x][i]=s[f[x][i-1]][i-1]; } else if(s[x][i-1]
s[x][i-1])s2[x][i]=s2[f[x][i-1]][i-1]; else s2[x][i]=s[x][i-1]; } else s[x][i]=s[x][i-1],s2[x][i]=max(s2[x][i-1],s2[f[x][i-1]][i-1]); } for(register int i=head[x];i;i=g[i].ne)if(g[i].to!=fa)s[g[i].to][0]=g[i].w,DFS(g[i].to,x);}struct Pair{int x,y;};inline Pair LCA(int x,int y){ if(dep[x]
=0;--i)if(dep[f[x][i]]>=dep[y]){ if(s[x][i]>ans){if(s2[x][i]>ans)ans=s[x][i],ans2=s2[x][i];else ans2=ans,ans=s[x][i];} else if(s[x][i]<=ans){if(s[x][i]>ans2)ans2=s[x][i];} x=f[x][i]; } if(x==y)return Pair{ans,ans2}; for(register int i=LOG-1;i>=0;--i)if(f[x][i]!=f[y][i]){ if(s[x][i]>ans){if(s2[x][i]>ans)ans=s[x][i],ans2=s2[x][i];else ans2=ans,ans=s[x][i];} else if(s[x][i]<=ans){if(s[x][i]>ans2&&s[x][i]!=ans)ans2=s[x][i];} if(s[y][i]>ans){if(s2[y][i]>ans)ans=s[y][i],ans2=s2[y][i];else ans2=ans,ans=s[y][i];} else if(s[y][i]<=ans){if(s[y][i]>ans2&&s[y][i]!=ans)ans2=s[y][i];} x=f[x][i];y=f[y][i]; } if(s[x][0]>ans){if(s2[x][0]>ans)ans=s[x][0],ans2=s2[x][0];else ans2=ans,ans=s[x][0];} else if(s[x][0]<=ans){if(s[x][0]>ans2&&s[x][0]!=ans)ans2=s[x][0];} if(s[y][0]>ans){if(s2[y][0]>ans)ans=s[y][0],ans2=s2[y][0];else ans2=ans,ans=s[y][0];} else if(s[y][0]<=ans){if(s[y][0]>ans2&&s[y][0]!=ans)ans2=s[y][0];}//错误笔记:必须判断一下是s[y][0]!=ans,才能保证严格 x=f[x][0];y=f[y][0];return Pair{ans,ans2};}int main(){#ifndef ONLINE_JUDGE freopen("BZOJ1977.in","r",stdin);freopen("BZOJ1977.out","w",stdout);#endif read(n),read(m); for(register int i=1;i<=m;++i)read(G[i].x),read(G[i].y),read(G[i].z); Kruskal();DFS(1); for(register int i=1;i<=m;++i)if(!intr[i]){ x=G[i].x,y=G[i].y,z=G[i].z; Pair p=LCA(x,y); if(z>p.x)SMIN(ans,sum-p.x+z); else if(z==p.x&&z>p.y)SMIN(ans,sum-p.y+z); } write(ans);putc('\n');}

转载于:https://www.cnblogs.com/hankeke/p/BZOJ1977.html

你可能感兴趣的文章
【java】对象变成垃圾被垃圾回收器gc收回前执行的操作:Object类的protected void finalize() throws Throwable...
查看>>
数据库建表练习(10.11作业)
查看>>
如何配置能让fiddler抓去https的请求?
查看>>
SpringBoot 2.0 更优雅的配置注入
查看>>
[慢查优化]联表查询注意谁是驱动表 & 你搞不清楚谁join谁更好时请放手让mysql自行判定...
查看>>
liunx之Centos6.8杀毒软件的安装
查看>>
充实的日子里忙忙碌碌
查看>>
十三、oracle 数据字典和动态性能视图
查看>>
插件开发-UI插件开发
查看>>
[转] vim自定义配置 和 在ubnetu中安装vim
查看>>
Windows环境下安装、卸载Apache
查看>>
HTTPS协议在Tomcat中启用的配置
查看>>
Collections.sort的使用
查看>>
圆形坠落模拟算法设计
查看>>
vi @-function
查看>>
2018年各大互联网前端面试题五(今日头条)
查看>>
Vue.js开发环境搭建的介绍
查看>>
python之路-SQLAlchemy
查看>>
python学习(九) 网络编程学习--简易网站服务器
查看>>
经典MapReduce作业和Yarn上MapReduce作业运行机制
查看>>