题目大意:
给一些没安排权值的边和安排了权值的边,没被安排的边全要被选入最小生成树,问你最大能把它们的权值和安排成多少。
题目分析:
假设建好了树,那么树边与剩下的每一条边都能构成一个环,并且非树边的权值是环中最大的,所以钦定边权不大于非树边即可。用并查集维护一下。
代码:
#include<bits/stdc++.h>
using namespace std; const int maxn = ; int n,k,m;
struct edge{int from,to,w;}p1[maxn],p2[maxn];
int pre[maxn],arr[maxn],minn[maxn],dep[maxn],fa[maxn],fd[maxn];
vector<int> g[maxn]; int found(int x){
int rx = x; while(pre[rx] != rx) rx = pre[rx];
while(pre[x] != rx){int tmp = pre[x]; pre[x] = rx; x = tmp;}
return rx;
} void read(){
scanf("%d%d%d",&n,&k,&m);
for(int i=;i<=k;i++){scanf("%d%d",&p1[i].from,&p1[i].to);}
for(int i=;i<=m;i++){scanf("%d%d%d",&p2[i].from,&p2[i].to,&p2[i].w);}
} void dfs(int now,int dp,int f){
dep[now] = dp; fa[now] = f;
for(int i=;i<g[now].size();i++){
int to;int z = g[now][i];
if(z > ){
if(p1[z].to == now) to = p1[z].from;
else to = p1[z].to;
}else{
if(p2[-z].to == now) to = p2[-z].from;
else to = p2[-z].to;
}
if(to == f) continue;
if(z) fd[to] = z;
dfs(to,dp+,now);
}
} void work(){
for(int i=;i<=n;i++) pre[i] = i;
for(int i=;i<=k;i++){
if(found(p1[i].from) != found(p1[i].to)){
pre[found(p1[i].from)] = found(p1[i].to);
g[p1[i].from].push_back(i); g[p1[i].to].push_back(i);
}
}
for(int i=;i<=m;i++){
if(found(p2[i].from) != found(p2[i].to)){
pre[found(p2[i].from)] = found(p2[i].to);
g[p2[i].from].push_back(-i); g[p2[i].to].push_back(-i);
arr[i] = ;
}
}
dfs(,,);
for(int i=;i<=n;i++) minn[i] = ,pre[i]=i;
for(int i=;i<=m;i++){
if(arr[i] == ){
int u = found(p2[i].from),v = found(p2[i].to);
while(u != v){
if(dep[u] >= dep[v]){
int z = found(fa[u]);
if(z!=)pre[u] = z; minn[fd[u]] = p2[i].w; u = z;
}else{
int z = found(fa[v]);
if(z!=)pre[v] = z; minn[fd[v]] = p2[i].w; v = z;
}
}
}
}
long long ans = ;
for(int i=;i<=k;i++){
if(minn[i] == ) {puts("-1");return;}
else ans += minn[i];
}
printf("%I64d",ans);
} int main(){
read();
work();
return ;
}