描述

有一个无向图,有n个点,m1条第一类边和m2条第二类边。第一类边有边权,第二类边无边权。请为第二类的每条边定义一个边权,使得第二类边可能全部出现在该无向图的最小生成树上,同时要求第二类边的边权总和尽可能大。
注:第二类边不会形成环

输入

第一行三个数n,m2,m1

接下来m2行,每行两个数,描述一条第二类边,分别表示两个端点接下来m1行,每行三个数,描述一条第一类边,分别表示两个端点和边权

对于30%的数据,n ≤ 5

对于60%的数据,n ≤ 1000

对于100%的数据,1 ≤ n ≤ 100000, m1 ≤ 2 × n, m2 < n

输出

输出一个数,表示第二类边的权值总和最大可能为多少。(若可能为无穷大则输出-1)

样例输入
5 2 3
1 2
4 5
2 3 100
3 4 100
1 5 1000
样例输出
2000

思路:我们先把第二类(B)和第一类(A)按权值排序,生成一个最小生成树,那么,对于第一类里面的那些没有被加入到树里的边e,我们需要保证这些边的两端在树上的路径e.u->e.v上的所有A类边都不大于e.cost。

所以我们需要去更新A类边的权值,我们把A类边都的权值都设为inf,然后用e.cost去更新,更新的过程就是势能线段树,如果区间有inf,那么就更新,否则跳过这个区间,因为每个A类边最多被跟新一次,势能会变小,这样可以保证复杂度。

(开始一直在想持久化并查集或者LCT...赶脚做不出来,然后才写了这个又长又臭的代码。求更简单的方法。qwq

(补充,好像不用线段树啊,直接用并查集找祖先里第一个A类边即可...

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
const int inf=1e9;
int x[maxn],y[maxn],Laxt[maxn],Next[maxn],To[maxn],Len[maxn];
int fa[maxn],Mx[maxn],tot,N,cnt,dep[maxn];
int a[maxn],sz[maxn],son[maxn],Top[maxn],p[maxn],q[maxn];
struct in{ int u,v,cost; }s[maxn];
bool cmp(in p,in q){ return p.cost<q.cost;}
int ff[maxn]; int find(int x){if(x==ff[x]) return x; return ff[x]=find(ff[x]);}
void add(int u,int v,int c){
Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=c;
}
void dfs1(int u,int f){
dep[u]=dep[f]+; fa[u]=f; sz[u]=;
for(int i=Laxt[u];i;i=Next[i])
if(To[i]!=f) {
dfs1(To[i],u),sz[u]+=sz[To[i]];
a[To[i]]=Len[i];
if(sz[To[i]]>sz[son[u]]) son[u]=To[i];
}
}
void dfs2(int u,int top)
{
Top[u]=top; p[++tot]=u; q[u]=tot;
if(son[u]) dfs2(son[u],top);
for(int i=Laxt[u];i;i=Next[i]){
if(To[i]!=son[u]&&dep[To[i]]>dep[u])
dfs2(To[i],To[i]);
}
}
void build(int Now,int L,int R)
{
if(L==R) { Mx[Now]=a[p[L]]; return ;}
int Mid=(L+R)>>;
build(Now<<,L,Mid); build(Now<<|,Mid+,R);
Mx[Now]=max(Mx[Now<<],Mx[Now<<|]);
}
int query(int Now,int L,int R,int l,int r)
{
if(Mx[Now]<inf) return ;
if(L==R){Mx[Now]=; return ;}
int Mid=(L+R)>>,res=;
if(l<=Mid) res+=query(Now<<,L,Mid,l,r);
if(r>Mid) res+=query(Now<<|,Mid+,R,l,r);
Mx[Now]=max(Mx[Now<<],Mx[Now<<|]);
return res;
}
int Query(int u,int v)
{
int f1=Top[u],f2=Top[v],res=;
while(f1!=f2){
if(dep[f1]<dep[f2]) swap(f1,f2),swap(u,v);
res+=query(,,N,q[f1],q[u]);
u=fa[f1]; f1=Top[u];
}
if(u!=v){
if(dep[u]>dep[v]) swap(u,v);
res+=query(,,N,q[son[u]],q[v]);
}
return res;
}
int main()
{
int A,B; ll ans=;
scanf("%d%d%d",&N,&A,&B);
rep(i,,N) ff[i]=i;
rep(i,,A){
scanf("%d%d",&x[i],&y[i]);
int fu=find(x[i]),fv=find(y[i]);
ff[fu]=fv;
add(x[i],y[i],inf); add(y[i],x[i],inf);
}
rep(i,,B) scanf("%d%d%d",&s[i].u,&s[i].v,&s[i].cost);
sort(s+,s+B+,cmp);
rep(i,,B) {
int fu=find(s[i].u),fv=find(s[i].v);
if(fu==fv) s[++tot]=s[i];
else { ff[fu]=fv;
add(s[i].u,s[i].v,s[i].cost);
add(s[i].v,s[i].u,s[i].cost);
}
}
B=tot; tot=;
dfs1(,); dfs2(,);
build(,,N); tot=;
rep(i,,B){
tot=Query(s[i].u,s[i].v);
ans+=(ll)tot*s[i].cost;
}
if(Mx[]==inf) puts("-1");
else printf("%lld\n",ans);
return ;
}

最新文章

  1. 【转】centos关机与重启命令详解
  2. [RDLC]报表根据字段列动态加载图片(二)
  3. Win7下配置nginx和php5
  4. Apache Tomcat8必备知识
  5. (转) Class
  6. 网页代码DIV+CSS布局积累
  7. javascript瀑布流
  8. linux——网络基础
  9. c#Socket客户端和服务端的信息发送
  10. 一天一个Linux命令--nmcli
  11. Django contenttypes组件
  12. MemcachedUI-一款基于.NET MVC编写的Memcached监控软件
  13. 第27月第6天 gcd timer
  14. Alpha冲刺随笔五:第五天
  15. java的InputStream和OutputStream的理解
  16. 在 Laravel 5 中集成七牛云存储实现云存储功能
  17. MVC 如何在action中获取当前网站的根路径
  18. C# 实例化类的执行顺序
  19. GNOME下也是Alt+F2,输入gnome-terminal
  20. C++(二十五) — 类的封装、实现

热门文章

  1. Thunder团队Final版本控制
  2. 基于 Flutter 以两种方式实现App主题切换
  3. English trip -- VC(情景课)9 D Reading 阅读练习
  4. CentOS7.6 Install TensorFlow
  5. TCP/IP四层与OSI七层模型
  6. Leetcode 105
  7. HDOJ1008
  8. 项目构建工具gradle
  9. WebForm页面数据绑定总结
  10. 如何解决Css属性text-overflow:ellipsis 不起作用(文本溢出显示省略号)