题面



$ solution: $

这道题很奇妙,需要对kruskal重构树有足够的了解!我们先对王牌电缆实行kruskal重构树,然后我们再来枚举每一条李牌电缆,我们将某一条李牌电缆加进这棵树中必然构成一颗基环树,然后我们必须在这个环上去掉一条王牌电缆,而这我们就可以用树上倍增来完成了!(这样做是正确的,仔细想一下为什么我们kruskal重构的树一定是最优解)



$ code: $

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set> #define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int using namespace std; struct su{ //王牌电线
int x,y,v,z;
inline bool operator <(su x){return v<x.v;}
}a[200005]; struct pi{ //树的边
int to,next,v,z;
}k[100005]; struct ya{ //倍增求LCA
int x,v,z;
}f[100005][17],c; int n,w,l,top; //意义如题
int ans1,ans2,qu,li;//后两个是存的去的哪一条王牌电线以及对应加的那一条李牌电线
int s[100005]; //并查集
int q[100005]; //BFS预处理
int dp[100005]; //这个点的深度
int tou[100005]; //连接这个点的边
bool vis[100005]; //我又没有访问过
bool shu[200005]; //这条电线我会不会用 inline int qr(){ char ch; //快读
while((ch=getchar())<'0'||ch>'9');
int res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch^48);
return res;
} inline ya max(ya x,ya y){return x.v>y.v?x:y;}
inline ya max(ya x,ya y,ya z){return x.v>y.v?(x.v>z.v?x:z):(y.v>z.v?y:z);} inline void print(int x,int y){ //输出
printf("%d\n",x);
for(rg i=1;i<=w;++i)
if(shu[i])printf("%d\n",i);//有用这条王牌电线就输出
printf("%d\n",y);
} inline int get(int x){ //并查集
return s[x]==x?x:(s[x]=get(s[x]));
} inline void add(int x,int y,int v,int z){
k[++top]=pi{y,tou[x],v,z};
k[++top]=pi{x,tou[y],v,z};
tou[y]=top; tou[x]=top-1;//加双向边
} inline void yu(){ //树上倍增的预处理
q[1]=1;dp[1]=1;vis[1]=1;
int l=0,r=1,i;
while(l<r){ i=q[++l];
for(rg j=0;j<16;++j){
if(!f[f[i][j].x][j].x)break;
f[i][j+1]=max(f[i][j],f[f[i][j].x][j]);
f[i][j+1].x=f[f[i][j].x][j].x;//注意先后顺序防覆盖
}
for(rg j=tou[i];j;j=k[j].next){
if(vis[k[j].to])continue;
int to=k[j].to;
f[to][0].z=k[j].z;
f[to][0].v=k[j].v;
f[to][0].x=i;//
dp[to]=dp[i]+1;
vis[to]=1; q[++r]=to;//
}
}
} inline ya ask(int x,int y){ //最近公共祖先,及其路径上的最大边权
if(dp[x]<dp[y])swap(x,y);
ya res; res.v=0;
for(rg i=16;i>=0;--i)
if(dp[f[x][i].x]>=dp[y])
res=max(res,f[x][i]),x=f[x][i].x;
for(rg i=16;i>=0;--i)
if(f[x][i].x!=f[y][i].x){
res=max(res,f[x][i]);//先取值再更新x
res=max(res,f[y][i]);
x=f[x][i].x,y=f[y][i].x;//注意先后
}else if(x==y)return res;
return max(res,f[x][0],f[y][0]);
} inline void kruskal(){ int t=0;
for(rg i=1;i<=n;++i)s[i]=i;//最小生成树
for(rg i=1;i<=w;++i)
if(get(a[i].x)!=get(a[i].y)){
s[get(a[i].x)]=get(a[i].y);
add(a[i].x,a[i].y,a[i].v,a[i].z);
shu[a[i].z]=1;ans1+=a[i].v;++t; //我们需要同时记住这条边的信息
}
if(t==n-1)return ;
rg x,y,v,j; ans2=inf;//仅靠王牌不能联通就直接枚举用那条李边划算
for(rg i=1;i<=l;++i){
x=qr(),y=qr(),v=qr();
if(get(x)!=get(y)&&ans2>v) ans2=v,j=i;//能用的权值最小的
}print(ans2+ans1,j),exit(0);
} int main(){
freopen("telephone.in","r",stdin);
freopen("telephone.out","w",stdout);
n=qr(),w=qr(),l=qr();
for(rg i=1;i<=w;++i)
a[i]=su{qr(),qr(),qr(),i};
sort(a+1,a+w+1);kruskal();yu();//排序,最小生成树,预处理
for(rg i=1,v;i<=l;++i){ //
c=ask(qr(),qr()); v=qr();
if(!li||ans2>ans1-c.v+v){//更新最优解
ans2=ans1-c.v+v;
shu[qu]=1;shu[c.z]=0;//要把上一个去掉的加回来!
li=i; qu=c.z;//记录去掉那条边,加上那条边
}
}print(ans2,li);//输出
return 0;
}

jzoj4313 电话线铺设(最小生成树+最近公共祖先)的更多相关文章

  1. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  2. NOIp 图论算法专题总结 (1):最短路、最小生成树、最近公共祖先

    系列索引: NOIp 图论算法专题总结 (1) NOIp 图论算法专题总结 (2) NOIp 图论算法专题总结 (3) 最短路 Floyd 基本思路:枚举所有点与点的中点,如果从中点走最短,更新两点间 ...

  3. 线段树、最短路径、最小生成树、并查集、二分图匹配、最近公共祖先--C++模板

    线段树(区间修改,区间和): #include <cstdio> #include <iostream> #include <cstring> using name ...

  4. D5 LCA 最近公共祖先

    第一题: POJ 1330 Nearest Common Ancestors POJ 1330 这个题可不是以1为根节点,不看题就会一直wa呀: 加一个找根节点的措施: #include<alg ...

  5. 0x63树的直径与最近公共祖先

    凉 bzoj1999 先把树的直径求出来,从左往右枚举,对于当前位置i,找到满足限制并且最远的点j,当前位置最大值就是max(i~j区间内除直径外的子树路径长度最大值,1~i的长度,j~n的长度) 然 ...

  6. lca最近公共祖先与树上倍增。

    https://vjudge.net/contest/295298#problem/A lca 的题目 求任意两点的距离. A题是在线算法,用st表rmq来实现. https://blog.csdn. ...

  7. LCA最近公共祖先 ST+RMQ在线算法

    对于一类题目,是一棵树或者森林,有多次查询,求2点间的距离,可以用LCA来解决.     这一类的问题有2中解决方法.第一种就是tarjan的离线算法,还有一中是基于ST算法的在线算法.复杂度都是O( ...

  8. 【转】最近公共祖先(LCA)

    基本概念 LCA:树上的最近公共祖先,对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. RMQ:区间最小值查询问题.对于长度为n的 ...

  9. 【并查集】【树】最近公共祖先LCA-Tarjan算法

    最近公共祖先LCA 双链BT 如果每个结点都有一个指针指向它的父结点,于是我们可以从任何一个结点出发,得到一个到达树根结点的单向链表.因此这个问题转换为两个单向链表的第一个公共结点(先分别遍历两个链表 ...

随机推荐

  1. Java之相对路径找不到文件问题解决方法

    1.问题: 在程序需要通过相对路径引用文件,使用Junit可以正常执行,但是直接使用main方法找不到对应问题. 2.分析: 因为不同运行方式所使用的环境变量中的用户工作目录不同所致. 3.解决: 修 ...

  2. 英国电信反悔华为是唯一真正的5G供应商

    导读 英国电信反悔华为是唯一真正的5G供应商 英国电信的一位发言人表示,该公司目前正「从我们自 2006 年以来实施的网络架构原则中,从我们的 3G 和 4G 网络核心提取华为设备」. 英国电信已经不 ...

  3. Educational Codeforces Round 25 A,B,C,D

    A:链接:http://codeforces.com/contest/825/problem/A 解题思路: 一开始以为是个进制转换后面发现是我想多了,就是统计有多少个1然后碰到0输出就行,没看清题意 ...

  4. ANDROID OptionMenu 菜单列表

    package com.app.menu; import android.os.Bundle; import android.app.Activity; import android.content. ...

  5. React Native——组件的生命周期

    组件生命周期 上流程图描述了组件从创建.运行到销毁的整个过程,可以看到如果一个组件在被创建,从开始一直到运行会依次调用getDefaultProps到render这五个函数:在运行过程中,如果有属性和 ...

  6. 洛谷 P2515 [HAOI2010]软件安装 解题报告

    P2515 [HAOI2010]软件安装 题目描述 现在我们的手头有\(N\)个软件,对于一个软件\(i\),它要占用\(W_i\)的磁盘空间,它的价值为\(V_i\).我们希望从中选择一些软件安装到 ...

  7. 监控(2)-php-fpm进程监控 shell

    #!/bin/bash #监控的网页地址url="http://dev2.jwsmed.com" #fastcgi启动/重启/停止脚本路径PROG=/data/fistsoft/p ...

  8. 使用kubeadm部署kubernetes1.9.1+coredns+kube-router(ipvs)高可用集群

    由于之前已经写了两篇部署kubernetes的文章,整个过程基本一致,所以这篇只着重说一下coredns和kube-router的部署. kube version: 1.9.1 docker vers ...

  9. Linux:进程实例信息(/proc)

    https://blog.csdn.net/test1280/article/details/73632333 Linux:进程实例信息(/proc) 问几个问题: 1.怎么知道一个进程对应哪个可执行 ...

  10. Python数据类型(数字和字符串)

    1.1 Number(数字) Python可以处理任意大的整数,包括负整数. 浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的.,比如,\(1.23\ti ...