最小生成树

112 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Boruvka’s Algorit
给每个点先找一个最小的边染色一定是若干个树,每个树里有一个重边每个联通块缩点n至少/2做log次

对这个问题套用Boruvka算法会变成什么?每个点有一个颜色,询问每个点和不同颜色的边权最小值同样用扫描线加线段树处理这个事情, 不过怎么处理不同颜色这个限制,记录最优值的时候顺便记录一个和最优值不同颜色的次优值时间复杂度nlog^2n, 要卡常

#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define pb push_back
typedef double db;
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=1e5+10;
const ll INF=1ll<<60;
struct event{int l,r,v;};
vector<event> s[MAXN];
ll tag[MAXN<<2];
int n,q,w,f[MAXN];
struct node{ll val;int id,col;}
seg[MAXN<<2][2],mp[MAXN],init;
int find(int x)
{return f[x]==x?x:f[x]=find(f[x]);}
#define mid ((l+r)>>1)
#define ls k<<1
#define rs k<<1|1
#define lc k<<1,l,mid
#define rc k<<1|1,mid+1,r
void upd(int k,node t)
{
 if(t.val<seg[k][0].val)
 {
  if(t.col!=seg[k][0].col)
   seg[k][1]=seg[k][0];
  seg[k][0]=t;
 }
 else if(t.val<seg[k][1].val&&t.col!=seg[k][0].col) 
  seg[k][1]=t;
}
void pushup(int k)
{
 seg[k][0].val=seg[k][1].val=INF;
 upd(k,seg[ls][0]);upd(k,seg[ls][1]);
 upd(k,seg[rs][0]);upd(k,seg[rs][1]);
}
void pushdown(int k)
{
 seg[ls][0].val+=tag[k];
 seg[ls][1].val+=tag[k];
 seg[rs][0].val+=tag[k];
 seg[rs][1].val+=tag[k];
 tag[ls]+=tag[k];tag[rs]+=tag[k];tag[k]=0;
}
void build(int k,int l,int r)
{
 tag[k]=0;
 if(l==r)
 {seg[k][0]=(node){0,l,find(l)};seg[k][1]=init;return;}
 build(lc);build(rc);pushup(k);
}
void update(int a,int b,int k,int l,int r,int val)
{
 if(a<=l&&r<=b)
 {tag[k]+=val;seg[k][0].val+=val;seg[k][1].val+=val;return;}
 if(tag[k]) pushdown(k);
 if(a<=mid) update(a,b,lc,val);
 if(b>mid) update(a,b,rc,val);
 pushup(k);
}
int main()
{
 scanf("%d%d",&n,&q);
 init=(node){INF,0,0};
 for(int i=1;i<=n;i++) f[i]=i;
 for(int i=1;i<=q;i++)
 {
  int x1,y1,x2,y2,w;
  scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&w);
  s[x1].pb((event){x2,y2,w});s[y1+1].pb((event){x2,y2,-w});
  s[x2].pb((event){x1,y1,w});s[y2+1].pb((event){x1,y1,-w});
 }
 int cur=0;ll res=0;
 while(cur<n-1)
 {
  build(1,1,n);
  for(int i=1;i<=n;i++) mp[i]=init;
  for(int i=1;i<=n;i++)
  {
   for(auto j:s[i]) 
    update(j.l,j.r,1,1,n,j.v);
   int col=find(i);
   node tmp=seg[1][col==seg[1][0].col];
   if(tmp.val<mp[col].val) mp[col]=tmp;
  }
  for(int i=1;i<=n;i++)
  {
   if(!mp[i].id) continue;
   int fx=find(i),fy=find(mp[i].id);
   if(fx!=fy) f[fx]=fy,res+=mp[i].val,cur++;
  }
 }
 printf("%lld\n",res);
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值