[洛谷P4234]最小差值生成树

给定一个标号为从$1$到$n$的、有$m$条边的无向图,求边权最大值与最小值的差值最小的生成树。

做法类似魔法森林,首先求出来最小生成树,然后每次加入一条边,断掉环上最小边并更新答案

这个过程我用两个堆维护的

代码:

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 #define M 500010
  7 #define ls ch[x][0]
  8 #define rs ch[x][1]
  9 using namespace std;
 10 int n,m,ans,top,cnt;
 11 int st[M],f[M],fa[M],rev[M],minn[M],val[M],id[M],ch[M][2];
 12 struct node{int v;};
 13 priority_queue<node>q1,q2;
 14 bool operator < (node a1,node a2) {
 15     return a1.v>a2.v;
 16 }
 17 void heap_pop(int v) {
 18     q1.push((node){v});
 19 }
 20 void heap_push(int v) {
 21     q2.push((node){v});
 22 }
 23 int heap_top() {
 24     while(!q1.empty()) {
 25         int x1=q1.top().v,x2=q2.top().v;
 26         if(x1==x2) q1.pop(),q2.pop();
 27         else break;
 28     }
 29     return q2.top().v;
 30 }
 31 struct point{
 32     int u,v,w;
 33 }a[M];
 34 bool cmp(point a1,point a2) {
 35     return a1.w<a2.w;
 36 }
 37 int find(int x) {
 38     return fa[x]==x?x:fa[x]=find(fa[x]);
 39 }
 40 void update(int x) {
 41     minn[x]=val[x];id[x]=x;
 42     if(ls&&minn[ls]<minn[x]) minn[x]=minn[ls],id[x]=id[ls];
 43     if(rs&&minn[rs]<minn[x]) minn[x]=minn[rs],id[x]=id[rs];
 44 }
 45 void pushdown(int x) {
 46     if(rev[x]) {
 47         if(ls) rev[ls]^=1;
 48         if(rs) rev[rs]^=1;
 49         swap(ls,rs),rev[x]^=1;
 50     }
 51 }
 52 int get(int x) {
 53     return ch[f[x]][1]==x;
 54 }
 55 bool is_root(int x) {
 56     return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;
 57 }
 58 void rotate(int x) {
 59     int old=f[x],oldf=f[old],k=get(x);
 60     if(!is_root(old)) ch[oldf][ch[oldf][1]==old]=x;
 61     ch[old][k]=ch[x][k^1],f[ch[old][k]]=old;
 62     ch[x][k^1]=old,f[old]=x,f[x]=oldf;
 63     update(old),update(x);
 64 }
 65 void splay(int x) {
 66     st[top=1]=x;
 67     for(int i=x;!is_root(i);i=f[i]) st[++top]=f[i];
 68     for(int i=top;i>=1;i--) pushdown(st[i]);
 69     for(int fa;!is_root(x);rotate(x))
 70         if(!is_root(fa=f[x]))
 71             rotate(get(x)==get(fa)?fa:x);
 72 }
 73 void access(int x) {
 74     for(int y=0;x;y=x,x=f[x])
 75         splay(x),ch[x][1]=y,update(x);
 76 }
 77 void makeroot(int x) {
 78     access(x);splay(x);rev[x]^=1;
 79 }
 80 void spilt(int x,int y) {
 81     makeroot(x);access(y);splay(y);
 82 }
 83 void link(int x,int y) {
 84     makeroot(x);f[x]=y;splay(x);
 85 }
 86 void cut(int x,int y) {
 87     spilt(x,y);f[x]=ch[y][0]=0;
 88 }
 89 int query(int x,int y) {
 90     spilt(x,y);return id[y];
 91 }
 92 int main() {
 93     scanf("%d%d",&n,&m);
 94     for(int i=1;i<=m;i++) 
 95         scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
 96     sort(a+1,a+1+m,cmp);
 97     memset(minn,63,sizeof(minn));
 98     memset(val,63,sizeof(val));
 99     memset(&ans,0x7f,sizeof(ans));
100     for(int i=1;i<=n;i++) fa[i]=i;
101     for(int i=1;i<=m;i++) id[i+n]=i+n,val[i+n]=a[i].w;
102     for(int i=1;i<=m;i++) {
103         int x=a[i].u,y=a[i].v;
104         if(find(x)==find(y)) {
105             int ID=query(x,y);
106             cut(a[ID-n].u,ID),cut(a[ID-n].v,ID);
107             link(x,i+n),link(y,i+n);
108             heap_pop(val[ID]);
109             heap_push(val[i+n]);
110         }
111         else {
112             fa[find(x)]=find(y);
113             link(x,i+n),link(y,i+n);
114             heap_push(val[i+n]);
115             cnt++;
116         }
117         if(cnt==n-1) {
118             ans=min(ans,a[i].w-heap_top());
119         }
120     }
121     printf("%d\n",ans);
122     return 0;
123 }

 

转载于:https://www.cnblogs.com/Slrslr/p/10022180.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值