非严格次小生成树+严格次小生成树

非严格次小生成树:首先使用最小生成树算法将最小生成树求出来,将生成树建图,然后用倍增维护树上的最大值。 考虑将所有的非树边一次加入最小生成树,并将新边与最小生成树形成的环上最大的边给删了,记录答案,然后答案最小值即为非严格次小生成树。

这个代码并没有求非严格次小生成树,但是除了没有记录答案以外,其他都一样

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int maxn=2e5+10;
const int mod=1e9+7;
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 t,n,m,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1],tot;//此处邻接表存储最小生成树
int f[maxn],fa[maxn][25],maxx[maxn][25],sum,k,X,dep[maxn];
struct node{int x,y,val,flag;
}e[maxn];
inline bool cmpl(node a,node b){return a.val<b.val;
}
int get(int x){if(x==f[x]) return x;f[x]=get(f[x]);return f[x];
}
void add(int x,int y,int z){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;val[tot]=z;nxt[++tot]=fir[y];fir[y]=tot;to[tot]=x;val[tot]=z;
}
void dfs(int x){for(int i=0;i<=20;i++)fa[x][i+1]=fa[fa[x][i]][i];for(int i=0;i<=20;i++)maxx[x][i+1]=max(maxx[x][i],maxx[fa[x][i]][i]);for(int i=fir[x];i;i=nxt[i]){int y=to[i];if(y==fa[x][0]) continue;fa[y][0]=x;dep[y]=dep[x]+1;maxx[y][0]=val[i];dfs(y);}
}
int query(int x,int y){int shawn=0;if(dep[x]<dep[y]) swap(x,y);for(int i=21;i>=0;i--){if(dep[fa[x][i]]>=dep[y]){shawn=max(shawn,maxx[x][i]);x=fa[x][i];}}if(x==y) return shawn;for(int i=21;i>=0;i--){if(fa[x][i]!=fa[y][i]){shawn=max(shawn,max(maxx[x][i],maxx[y][i]));x=fa[x][i];y=fa[y][i];}}return max(shawn,max(maxx[x][0],maxx[y][0]));
}
int ksm(int x,int y){int tot=1;while(y){if(y&1) tot=(tot*x)%mod;x=x*x%mod;y>>=1;}return tot%mod;
}
signed main(){freopen("4.in","r",stdin);t=read();while(t--){memset(fir,0,sizeof(fir));memset(fa,0,sizeof(fa));memset(dep,0,sizeof(dep));memset(maxx,0,sizeof(maxx));n=read();m=read();X=read();for(int i=1;i<=m;i++){e[i].x=read();e[i].y=read();e[i].val=read();e[i].flag=0;}sort(e+1,e+1+m,cmpl);k=0;sum=0;for(int i=1;i<=n;i++) f[i]=i;for(int i=1,x,y,fx,fy;i<=m;i++){x=e[i].x;y=e[i].y;fx=get(x);fy=get(y);if(fx!=fy){f[fx]=fy;sum+=e[i].val;k++;e[i].flag=1;add(x,y,e[i].val);}if(k==n-1) break;}dfs(1);int now,equ=0,les=0;for(int i=1;i<=m;i++){if(!e[i].flag){now=sum+e[i].val-query(e[i].x,e[i].y);if(now==X) equ++;else if(now<X)les++;}}if(X==sum){printf("%lld\n",((ksm(2,m)-2*ksm(2,m-n+1-equ))%mod+mod)%mod);}else{printf("%lld\n",(2*(ksm(2,m-n+1-les)-ksm(2,m-n+1-les-equ))%mod)%mod);}}return 0;
}

严格次小生成树

与非严格次小生成树的唯一区别就是求了最小生成树上的次大值,倍增维护。

现在唯一的难点就是如何倍增维护次大值,用dis1[i][x]dis1[i][x]dis1[i][x] 表示最大值,dis2[i][x]dis2[i][x]dis2[i][x] 表示次大值,fa[i][x]fa[i][x]fa[i][x] 表示祖先

if(dis1[i][x]==dis1[i][fa[i][x]])dis2[i+1][x]=max(dis2[i][x],dis2[i][fa[i][x]])if(dis1[i][x]==dis1[i][fa[i][x]]) dis2[i+1][x]=max(dis2[i][x],dis2[i][fa[i][x]])if(dis1[i][x]==dis1[i][fa[i][x]])dis2[i+1][x]=max(dis2[i][x],dis2[i][fa[i][x]]) :显然,如果两段最大值相等,则次大值在两个最大值中产生

if(dis1[i][x]<dis1[i][fa[i][x]])dis2[i+1][x]=max(dis1[i][x],dis2[i][fa[i][x]])if(dis1[i][x]<dis1[i][fa[i][x]]) dis2[i+1][x]=max(dis1[i][x],dis2[i][fa[i][x]])if(dis1[i][x]<dis1[i][fa[i][x]])dis2[i+1][x]=max(dis1[i][x],dis2[i][fa[i][x]]) :显然,如果第二段最大值大于第一段最大值,则第二段最大值不可能成为次大值。因此次大值在第一段最大值和第二段次大值中产生。

if(dis1[i][x]>dis1[i][fa[i][x]])dis2[i+1][x]=max(dis2[i][x],dis1[i][fa[i][x]])if(dis1[i][x]>dis1[i][fa[i][x]])dis2[i+1][x]=max(dis2[i][x],dis1[i][fa[i][x]])if(dis1[i][x]>dis1[i][fa[i][x]])dis2[i+1][x]=max(dis2[i][x],dis1[i][fa[i][x]]) :同理

然后在加入新边,寻找环上最大边和次大边时,需要注意一下

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int INF=1e18;
const int maxn=6e5+10;
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,dep[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1],s,tot;
int fa[30][maxn],dis1[30][maxn],dis2[30][maxn],f[maxn],k,qaq,sum;
struct node{int x,y,z;bool flag;
}e[maxn];
void add(int x,int y,int z){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;val[tot]=z;}
inline bool cmpl(node a,node b){return a.z<b.z;
}
int get(int x){if(f[x]==x) return x;return f[x]=get(f[x]);
}
void dfs(int x){for(int i=0;i<=20;i++){fa[i+1][x]=fa[i][fa[i][x]];
//          if(x==6) cout << fa[i][x] << " " << fa[i][fa[i][x]] << endl;dis1[i+1][x]=max(dis1[i][x],dis1[i][fa[i][x]]);if(dis1[i][x]==dis1[i][fa[i][x]]){dis2[i+1][x]=max(dis2[i][x],dis2[i][fa[i][x]]);}else if(dis1[i][x]>dis1[i][fa[i][x]]){dis2[i+1][x]=max(dis2[i][x],dis1[i][fa[i][x]]);}else if(dis1[i][x]<dis1[i][fa[i][x]]){dis2[i+1][x]=max(dis1[i][x],dis2[i][fa[i][x]]);}}for(int i=fir[x];i;i=nxt[i]){int y=to[i];if(y==fa[0][x]) continue;fa[0][y]=x;dep[y]=dep[x]+1;//cout << "qaq" << x << " "<< y<<endl;dis1[0][y]=val[i];dis2[0][y]=-INF;dfs(y);}
}
void prepare_work(){for(int x=1;x<=n;x++){
//          if(x==6) cout << "qaq" << endl;for(int i=0;i<=20;i++){fa[i+1][x]=fa[i][fa[i][x]];
//          if(x==6) cout << fa[i][x] << " " << fa[i][fa[i][x]] << endl;dis1[i+1][x]=max(dis1[i][x],dis1[i][fa[i][x]]);if(dis1[i][x]==dis1[i][fa[i][x]]){dis2[i+1][x]=max(dis2[i][x],dis2[i][fa[i][x]]);}else if(dis1[i][x]>dis1[i][fa[i][x]]){dis2[i+1][x]=max(dis2[i][x],dis1[i][fa[i][x]]);}else if(dis1[i][x]<dis1[i][fa[i][x]]){dis2[i+1][x]=max(dis1[i][x],dis2[i][fa[i][x]]);}}}
}
int LCA(int x,int y){if(dep[x]<dep[y]) swap(x,y);for(int i=20;i>=0;i--){if(dep[fa[i][x]]>=dep[y]) x=fa[i][x];//,cout << x << " " << y << endl;}if(x==y) return x;for(int i=20;i>=0;i--){if(fa[i][x]!=fa[i][y]){x=fa[i][x];y=fa[i][y];//cout << x << " " << y << endl;}}return fa[0][x];
}
void check(int lca,int x,int val){int val1=0,val2=0;for(int i=20;i>=0;i--){if(dep[fa[i][x]]>=dep[lca]){if(dis1[i][x]>val1){val2=val1;val1=dis1[i][x];}val2=max(val2,dis2[i][x]);x=fa[i][x];}}if(val1!=val) qaq=min(qaq,val-val1);else qaq=min(qaq,val-val2);
}
signed main(){
//  freopen("tree.in","r",stdin);
//  freopen("own.out","w",stdout);n=read();m=read();for(int i=1;i<=m;i++){e[i].x=read();e[i].y=read();e[i].z=read();}sort(e+1,e+1+m,cmpl);for(int i=1;i<=n;i++) f[i]=i;for(int i=1;i<=m;i++){int x=e[i].x,y=e[i].y;int fx=get(x),fy=get(y);if(fx!=fy){k++;e[i].flag=true;f[fx]=fy;sum+=e[i].z;add(x,y,e[i].z);add(y,x,e[i].z);
//          if(!s) s=x;}if(k==n-1) break;}dep[1]=1;dfs(1);
//  prepare_work();qaq=INF;
//  for(int i=1;i<=n;i++){
//      for(int j=1;j<=5;j++){
//          cout << fa[j][i] << " ";
//      }
//      cout << endl;
//  }// for(int i=1;i<=n;i++) cout << dep[i] << " ";
//  cout << endl;for(int i=1;i<=m;i++){if(!e[i].flag){int x=e[i].x,y=e[i].y,lca;lca=LCA(x,y);
//          cout << x << " " << y << " "<< lca << endl;check(lca,x,e[i].z);check(lca,y,e[i].z);}}printf("%lld",sum+qaq);
}

非严格次小生成树+严格次小生成树相关推荐

  1. 解题报告:luogu P4180 [BJWC2010]严格次小生成树(次小生成树、倍增LCA优化、O(mlogn) )

    P4180 [BJWC2010]严格次小生成树 次小生成树有两种,一种是不严格次小生成树,也就是可以数值上等于最小生成树,一种是严格次小生成树,是权值严格大于最小生成树,两种求法大同小异. 方法2在严 ...

  2. 疯子的算法总结11--次小生成树+严格次小生成树

    一.总体思路 首先,我这一题的思路是倍增LCA+Kruskal 首先,kruskal求最小生成树  不会的戳这里 求次小生成树 倍增  LCA 关键在于次小生成树怎么求: 问自己一些问题 怎么求不严格 ...

  3. 【POJ1679】The Unique MST(非严格次小生成树)

    problem 给出一个连通无向图,判断它的最小生成树是否唯一 如果唯一,输出生成树的大小,否则输出"Not Unique!" solution 直接求非严格次小生成树 如果次小生 ...

  4. 一棵树的生成树有几颗_次小生成树(树剖,生成树)

    生成树的概念: 在一个无向图中,设顶点数为\(n\),取其中\(n-1\)条边并使所有点相连,所得到的一棵树即为生成树. 最小生成树: 如果还没有接触过生成树的同学,欢迎戳->最小生成树详解 次 ...

  5. 次小生成树(Prim + Kruaskal)

    问题引入: 我们先来回想一下生成树是如何定义的,生成树就是用n - 1条边将图中的所有n个顶点都连通为一个连通分量,这样的边连成子树称为生成树. 最小生成树很明显就是生成树中权值最小的生成树,那么我们 ...

  6. NYOJ 118 修路方案(次小生成树)

    修路方案 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路. ...

  7. 【转】小生我怕怕工具包[2010.06.17](转自52破解论坛)

    该破解工具包是52破解论坛的斑竹小生我怕怕搜集制作,喜欢的可以下了啊------------------------------------------------------------------ ...

  8. XJOI 3629 非严格次小生成树(pqq的礼物)

    题目描述: 有一天,pqq准备去给×i×准备礼物,他有一些礼品准备包装一下,他用线将这些礼物连在一起,不同的礼物因为风格不同所以连接它们需要不同价值的线.风格差异越大,价格越大(所以两个礼物之间只有一 ...

  9. 非严格次小生成树 pqq的礼物

    题目描述 吐槽一下 思考人生 安利一发 题目描述 有一天,pqq准备去给×i×准备礼物,他有一些礼品准备包装一下,他用线将这些礼物连在一起,不同的礼物因为风格不同所以连接它们需要不同价值的线.风格差异 ...

最新文章

  1. file_put_contents图片固定大小_创意图片裁剪,神一样的操作
  2. TCP三次握手连接及seq和ack号的正确理解
  3. (找水王)编程思维训练
  4. 使用 ML.NET 识别乐高颜色块
  5. vue cli3 兼容ie8以上浏览器,前端兼容;解决ie浏览器下白屏问题
  6. 自动驾驶安全驾驶规则_自动驾驶知识科普 自动驾驶汽车的七大核心技术
  7. Java多线程:解决生产者/消费者模式
  8. 金色金箔高品质纹理素材,将在你的下一个设计项目中被使用。
  9. LeetCode 300最长递增子序列
  10. linux重新初始化mysql 并修改大小写铭感_在Linux(Centos 7)环境下安装Mysql的完整过程...
  11. 中科易安:公安对接流动人口管理智能锁需要联网吗?
  12. Python项目实战:使用selenium爬取拉勾网数据
  13. 电脑安装哪款linux系统好,四款linux操作系统总有一款适合你
  14. linux加新的硬盘,linux添加新硬盘
  15. Java-toArray()方法
  16. TextView与EditText
  17. 小旋风蜘蛛池X6.21去除授权站群+修复空白+弹窗
  18. Ant Design Vue 相关介绍
  19. Java实现数据库读写分离
  20. JavaScript的压缩

热门文章

  1. 连续七年 领跑未来丨山石网科入选Gartner 2020网络防火墙魔力象限
  2. 【IoT-卫朋】智能硬件 | 产品按键设计
  3. 介绍了用Meta标签代码让360双核浏览器默认极速模式(google)打开网站不是兼容模式
  4. python 全栈开发,Day106(结算中心(详细),立即支付)
  5. TX云游戏平台 WeGame 1.0.3.8中文版
  6. Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)
  7. 游戏开发中字典数据的优化方案 golang版本
  8. excel查询oracle数据库,用Excel直接查询Oracle中的数据
  9. 手机耳机插入电脑没有反应
  10. 微信公众号学习与开发过程