Description
Input
Output
Sample Input
6 9 4
6 3 4
2 5 6
5 4 6
1 3 5
3 5 9
5 6 8
4 1 5
4 6 4
6 2 7
2 5 3
1 5 4
4 5 4
3 2 5
Sample Output
22
1
8
4
3
1
Data Constraint
题解
我们先对全部的“王牌电缆”建一颗最小生成树
那么对于要加如来的一条“李牌电缆”,一定会使最小生成树形成一个环(除数据12、13点外)
如果要使最后得出来的解最小,那么就是要删掉在加入该条“李牌电缆”后形成环上最大的边
那么我们如果找到这个环?
易得,如果连接“李牌电缆”两点的最近公共祖先,和这两个点围成的就是要求得的环
那么,我们可以用倍增求Lca,可支持O(log n),询问两点之间的费用最大的边权
(Tips:
如果存在只用“王牌电缆”无法联通整个小区的数据
直接枚举加入最小生成数里
取最小值输出
)
拓展 :树上倍增求LCA
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=800007;
const int inf=0x7fffffff;
int l,t,n,m,w,e,num,x,y,z,mn,mnn,mnm;
int father[maxn],ans,first[maxn],next[maxn],last[maxn],total,zhi[maxn];
int x1[maxn],y1[maxn],z1[maxn],f[maxn][20],k[maxn][20],aa,g[maxn][20],xu[maxn];
int ans1[maxn],bb,deep[maxn];
struct edge{int v,d,l,r;}a[maxn];
bool cmp(edge x,edge y){ return (x.v<y.v)||(x.v==y.v&&x.l<y.l)||(x.v==y.v&&x.l==y.l&&x.r<y.r); }
int getfather(int x)
{
if (!father[x]) return x;
father[x]=getfather(father[x]);
return father[x];
}
void insert(int x,int y,int z,int d)
{
last[++total]=y;
next[total]=first[x];
first[x]=total;
zhi[total]=z;
xu[total]=d;
last[++total]=x;
next[total]=first[y];
first[y]=total;
zhi[total]=z;
xu[total]=d;
}
void dfs(int x,int y)
{
f[x][0]=y; deep[x]=deep[y]+1;
for (int i=first[x];i;i=next[i])
if (last[i]!=y)
{
dfs(last[i],x);
k[last[i]][0]=zhi[i];
g[last[i]][0]=xu[i];
}
}
int lca(int x,int y)
{
int w=0;
if (deep[x]<deep[y]) swap(x,y);
for (int i=19;i>=0;i--)
if (deep[f[x][i]]>deep[y])
{
bb=(k[x][i]>w?g[x][i]:bb);
w=max(w,k[x][i]);
x=f[x][i];
}
if (deep[x]!=deep[y])
{
bb=(k[x][0]>w?g[x][0]:bb);
w=max(w,k[x][0]);
x=f[x][0];
}
for (int i=19;i>=0;i--)
if(f[x][i]!=f[y][i])
{
bb=(k[x][i]>w?g[x][i]:bb);
w=max(w,k[x][i]);
bb=(k[y][i]>w?g[y][i]:bb);
w=max(w,k[y][i]);
x=f[x][i];
y=f[y][i];
}
if (x!=y)
{
bb=(k[x][0]>w?g[x][0]:bb);
w=max(w,k[x][0]);
bb=(k[y][0]>w?g[y][0]:bb);
w=max(w,k[y][0]);
}
aa=w;
if (x!=y) return f[x][0]; else return x;
}
int main()
{
freopen("telephone.in","r",stdin);
freopen("telephone.out","w",stdout);
scanf("%d%d%d",&n,&w,&l);
for (int i=1;i<=w;i++)
{
scanf("%d%d%d",&x,&y,&z);
if (x>y) swap(x,y);
a[++num].l=x; a[num].r=y; a[num].v=z; a[num].d=i;
}
sort(a+1,a+num+1,cmp);
for (int i=1;i<=l;i++) scanf("%d%d%d",&x1[i],&y1[i],&z1[i]);
mn=inf;
for (int i=1;i<=num;i++)
{
x=getfather(a[i].l); y=getfather(a[i].r);
if (x!=y)
{
father[y]=x;
m++;
ans+=a[i].v;
ans1[m]=a[i].d;
insert(a[i].l,a[i].r,a[i].v,a[i].d);
}
if (m==n-1) break;
}
if (m==n-2)
{
for (int i=1;i<=l;i++)
{
x=getfather(x1[i]); y=getfather(y1[i]);
if (x!=y&&z1[i]<mn)
{
mn=z1[i];
mnn=i;
}
}
printf("%d
",ans+mn);
for (int i=1;i<=m;i++) printf("%d
",ans1[i]);
printf("%d
",mnn);
return 0;
}
dfs(1,0);
for (int j=1;j<=19;j++)
for (int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
if (f[i][j]) g[i][j]=(k[i][j-1]>k[f[i][j-1]][j-1]?g[i][j-1]:g[f[i][j-1]][j-1]);
if (f[i][j]) k[i][j]=max(k[i][j-1],k[f[i][j-1]][j-1]);
}
for (int i=1;i<=l;i++)
{
int fa=lca(x1[i],y1[i]);
if (z1[i]-aa<mn)
{
mn=z1[i]-aa;
mnn=i;
mnm=bb;
}
}
printf("%d
",ans+mn);
for (int i=1;i<=n-1;i++)
{
if (ans1[i]==mnm) continue;
printf("%d
",ans1[i]);
}
printf("%d
",mnn);
return 0;
}