问题陈述
有一个图,它有 N+QN+Q 个顶点,编号为 1,2,…,N+Q1,2,…,N+Q 。最初,该图没有边。
对于这个图,请依次对 i=1,2,…,Qi=1,2,…,Q 执行以下操作:
- 对于每个满足 Li≤j≤RiLi≤j≤Ri 的整数 jj ,在顶点 N+iN+i 和 jj 之间添加一条代价为 CiCi 的无向边。
完成所有操作后,确定图形是否相连。如果相连,求该图的最小生成树的代价。
最小生成树是成本最小的生成树,生成树的成本是生成树中所用边的成本之和。
限制因素
- 1≤N,Q≤2×1051≤N,Q≤2×105
- 1≤Li≤Ri≤N1≤Li≤Ri≤N
- 1≤Ci≤1091≤Ci≤109
- 所有输入值均为整数。
输出
如果图形是连通的,则打印最小生成树的代价。否则,打印 −1−1 。
做法
题目大意就是区间l到r的点可以和N+i的点连接一条价值为C的边,1<=i<=Q。首先我们如果单纯的把所有边建出来,然后跑最小生成树,那肯定是不行的,会超时。那我们肯定就想先贪心考虑建边代价小的。对于最小生成树,我们只需要连接n-1条边(那Q个点不算)。我们就用并查集维护,若有两个连通块没连接,那我们就连上。
#include<bits/stdc++.h>
using namespace std;
int n,q;
int fa[2000010];
struct ty{
int l,r;
long long c;
};
bool cmp(ty a,ty b){
return a.c<b.c;
}
int getfa(int x){
if(fa[x]==x) return x;
return fa[x]=getfa(fa[x]);
}
void setfa(int x,int y){
fa[getfa(x)]=getfa(y);
}
int main(){
scanf("%d%d",&n,&q);
vector<ty> v(q);
for(int i=0;i<q;i++){
scanf("%d%d%lld",&v[i].l,&v[i].r,&v[i].c);
}
sort(v.begin(),v.end(),cmp); //贪心
for(int i=1;i<=n;i++) fa[i]=i;
long long ans=0;
int cnt=n;
for(int i=0;i<v.size();i++){
ans+=v[i].c;//第一个点和第N+i个点连。必须连接,不然Q个点之间无法联通
for(int j=getfa(v[i].l)+1;j<=v[i].r;j=getfa(j)+1) {//找没连接的两个连通块
setfa(j-1,j);//大的点做父亲 ,不然无法实现
ans+=v[i].c;
cnt--;
}
}
if(cnt!=1) cout<<-1;//最小生成树至少要有n-1条边
else cout<<ans;
}