bzoj1977 [BeiJing2010]次小生成树 Tree(kruskal+树上倍增)
来源:互联网 发布:sql注入攻击登录 编辑:程序博客网 时间:2024/06/05 15:50
先求出最小生成树,注意要严格次小。。。
枚举每一条非树边,把他加进来然后删掉这条非树边连接的两点在树上原来的路径上的最大边(保证是次小),(如果最大边与非树边边权相同则找次大边,为了严格次小)然后更新最小增量。
最大边和次大边可以通过树上倍增求出
#include <bits/stdc++.h>using namespace std;#define ll long long#define inf 0x3f3f3f3f#define N 100010#define M 300010inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f;}int n,m,fa[N][18],f[N],h[N],num=0,mx1[N][18],mx2[N][18],Log[N],dep[N];ll ans=0,res=inf;struct edge{ int x,y,val;bool f;}e[M];struct Edge{ int to,next,val;}data[N<<1];inline void add(int x,int y,int val){ data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;}inline bool cmp(edge x,edge y){ return x.val<y.val;}inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}void dfs(int x){ for(int i=1;i<=Log[n];++i){ if(!fa[x][i-1]) break; fa[x][i]=fa[fa[x][i-1]][i-1]; mx1[x][i]=max(mx1[x][i-1],mx1[fa[x][i-1]][i-1]); if(mx1[x][i-1]==mx1[fa[x][i-1]][i-1]) mx2[x][i]=max(mx2[x][i-1],mx2[fa[x][i-1]][i-1]); else{ mx2[x][i]=min(mx1[x][i-1],mx1[fa[x][i-1]][i-1]); mx2[x][i]=max(mx2[x][i],max(mx2[x][i-1],mx2[fa[x][i-1]][i-1])); } } for(int i=h[x];i;i=data[i].next){ int y=data[i].to;if(y==fa[x][0]) continue; fa[y][0]=x;dep[y]=dep[x]+1;mx1[y][0]=data[i].val;dfs(y); }}int lca(int x,int y){ if(dep[x]<dep[y]) swap(x,y); int d=dep[x]-dep[y]; for(int i=0;i<=Log[d];++i) if(d&(1<<i)) x=fa[x][i]; if(x==y) return x; for(int i=Log[n];i>=0;--i) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0];}void calc(int x,int y,int val){//找路径最大边和次大边 int d=dep[x]-dep[y],res1=0,res2=0; for(int i=0;i<=Log[d];++i){ if(d&(1<<i)){ if(mx1[x][i]==res1) res2=max(res2,mx2[x][i]); else if(mx1[x][i]>res1){ res2=res1;res1=mx1[x][i]; res2=max(res2,mx2[x][i]); }else res2=max(res2,mx1[x][i]); } } if(res1==val) res=min(res,(ll)val-res2); else res=min(res,(ll)val-res1);}void solve(int x,int y,int val){ int t=lca(x,y); calc(x,t,val);calc(y,t,val);}int main(){// freopen("a.in","r",stdin); n=read();m=read(); for(int i=1;i<=m;++i) e[i].x=read(),e[i].y=read(),e[i].val=read(); sort(e+1,e+m+1,cmp);Log[0]=-1; for(int i=1;i<=n;++i) f[i]=i,Log[i]=Log[i>>1]+1; for(int i=1;i<=m;++i){ int xx=find(e[i].x),yy=find(e[i].y); if(xx!=yy){ f[xx]=yy;e[i].f=1;ans+=e[i].val; add(e[i].x,e[i].y,e[i].val);add(e[i].y,e[i].x,e[i].val); } }dfs(1); for(int i=1;i<=m;++i)//枚举非树边 if(!e[i].f) solve(e[i].x,e[i].y,e[i].val); printf("%lld\n",ans+res); return 0;}
阅读全文
0 0
- bzoj1977 [BeiJing2010]次小生成树 Tree(kruskal+树上倍增)
- bzoj1977: [BeiJing2010组队]次小生成树 Tree 树上倍增
- bzoj1977: [BeiJing2010]次小生成树 kruskal+倍增LCA
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree Kruskal+倍增LCA
- bzoj1977 [BeiJing2010组队]次小生成树 Tree (lca+倍增)
- 【bzoj1977】【次小生成树】【树上倍增】
- 1977: [BeiJing2010组队]次小生成树 Tree kruskal+倍增
- bzoj1977 [BeiJing2010组队]次小生成树 倍增
- [BZOJ1977][Beijing2010组队][LCA][Kruskal]次小生成树
- [BZOJ1977][BeiJing2010组队]次小生成树 Tree(kruskal+链剖)
- bzoj1977: [BeiJing2010组队]次小生成树 Tree
- bzoj1977: [BeiJing2010组队]次小生成树 Tree
- BZOJ1977: [BeiJing2010组队]次小生成树 Tree
- bzoj1977 [BeiJing2010组队]次小生成树 Tree
- BZOJ1977: [BeiJing2010组队]次小生成树 Tree
- BZOJ1977 [BeiJing2010组队] [次小生成树 Tree]
- [BZOJ1977]严格次小生成树-kruskal+倍增维护
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree【次小生成树】【LCA】
- 解决spring boot启动报错java.lang.NoClassDefFoundError: ch/qos/logback/classic/Level
- 斜率优化dp小结
- 题目49:开心的小明
- [总结]----Hive创建表格的几种方式
- 程序员把妹从入门到精通(一)
- bzoj1977 [BeiJing2010]次小生成树 Tree(kruskal+树上倍增)
- LED_1_1(流水灯)
- HDU1251(静态维护字典树模板题)
- c++设计一个分数类。要求:1.分类包含的分数运算有:连个分数的加、减、乘、除运算。
- 51NOD 1952 栈 【单调队列】
- 计算组合数的几种方法
- 真真感受到了c语言的古老!
- [总结]----Hive数据导入 六种方式
- 【Python】【matplotlib】绘图