jzoj4313 电话线铺设

15 篇文章 0 订阅
11 篇文章 0 订阅

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

这里写图片描述

算法讨论

因为李牌电缆只能用一根,所以先跑一次最小生成树,在枚举使用那根李牌电缆,删掉环上最大的王牌电缆,需要用lca记录第i个点条2^j步后的点以及路上的最大值,最大值的编号就可以了,但有可能所有王牌电缆不能连通小区,所以特判一定要一条李牌电缆,费用就是最小生成树的值直接加李牌电缆的花费。
type node=^link;
link=record
     g,qu,bian:longint;
     next:node;
end;
var
  nd:array[0..300000]of node;
  n,m,k,ans,s,bh:longint;
  fa,ma,gg:array[0..300000,0..18] of longint;
  flag:array[0..300000] of boolean;
  x,y,w,g,f,dep:array[0..300000] of longint;
procedure ad(u,v,w,h:longint);
var
  p:node;
begin
  new(p);
  p^.g:=v;
  p^.next:=nd[u];
  p^.qu:=w;
  p^.bian:=h;
  nd[u]:=p;
end;
procedure qs(l,r:longint);
var
  i,j,m,t:longint;
begin
  i:=l;j:=r;
  m:=w[(l+r) div 2];
  repeat
    while w[i]<m do inc(i);
    while w[j]>m do dec(j);
    if i<=j then
      begin
        t:=x[i];x[i]:=x[j];x[j]:=t;
        t:=y[i];y[i]:=y[j];y[j]:=t;
        t:=w[i];w[i]:=w[j];w[j]:=t;
        t:=g[i];g[i]:=g[j];g[j]:=t;
        inc(i);
        dec(j);
      end;
  until i>j;
  if l<j then qs(l,j);
  if i<r then qs(i,r);
end;

function find(z:longint):longint;
begin
  if f[z]=z then
    exit(z);
  f[z]:=find(f[z]);
  exit(f[z]);
end;
procedure zsscs;
var
  i,xx,yy:longint;
begin
  s:=0;
  for i:=1 to m do
    begin
      xx:=find(x[i]);
      yy:=find(y[i]);
      if xx<>yy then
        begin
          ans:=ans+w[i];
          f[xx]:=yy;
          inc(s);
          ad(x[i],y[i],w[i],g[i]);
          ad(y[i],x[i],w[i],g[i]);
          x[s]:=x[i];y[s]:=y[i];
          w[s]:=w[i];g[s]:=g[i];
        end;
    end;
end;
procedure dfs(wei,e:longint);
var
  p:node;
begin
  dep[wei]:=e;
  p:=nd[wei];
  flag[wei]:=false;
  while p<>nil do
    begin
      if flag[p^.g] then
        begin
          fa[p^.g,0]:=wei;
          ma[p^.g,0]:=p^.qu;
          gg[p^.g,0]:=p^.bian;
          dfs(p^.g,e+1);
        end;
      p:=p^.next;
    end;
end;
function faa(a,b:longint):longint;
var
  i,j,max:longint;
begin
  if dep[a]<dep[b] then
    begin
      i:=a;a:=b;b:=i;
    end;
  i:=dep[a]-dep[b];
  j:=0;
  max:=0;
  while i>0 do
    begin
      if i mod 2=1 then
        begin
          if ma[a,j]>max then
            begin
              max:=ma[a,j];
              bh:=gg[a,j];
            end;
          a:=fa[a,j];
        end;
       i:=i div 2;
       inc(j);
    end;
  if a=b then exit(max);
  j:=18;
  while fa[a,0]<>fa[b,0] do
    begin
      if fa[a,j]<>fa[b,j] then
        begin
          if ma[a,j]>max then
            begin
              max:=ma[a,j];
              bh:=gg[a,j];
            end;
          a:=fa[a,j];
          if ma[b,j]>max then
            begin
              max:=ma[b,j];
              bh:=gg[b,j];
            end;
          b:=fa[b,j];
        end;
      dec(j);
    end;
  if ma[a,0]>max then
    begin
      max:=ma[a,0];
      bh:=gg[a,0];
    end;
  if ma[b,0]>max then
    begin
      max:=ma[b,0];
      bh:=gg[b,0];
    end;
  exit(max);
end;
var
  i,j,min,u,v,t,sum,zz,tt,mb:longint;
  kk:boolean;
begin
  assign(input,'telephone.in');reset(input);
  assign(output,'telephone.out');rewrite(output);
  readln(n,m,k);
  for i:=1 to m do
    begin
      readln(x[i],y[i],w[i]);
      g[i]:=i;
    end;
  qs(1,m);
  for i:=1 to n do f[i]:=i;
  ans:=0;
  zsscs;
  mb:=find(1);
  for i:=2 to n do
    if find(i)<>mb then kk:=true;
  fillchar(flag,sizeof(flag),true);
  dfs(1,1);
  for i:=1 to 18 do
    for j:=1 to n do
      begin
        if fa[j,i-1]=0 then continue;
        fa[j,i]:=fa[fa[j,i-1],i-1];
        if ma[j,i-1]>ma[fa[j,i-1],i-1] then
          begin
            ma[j,i]:=ma[j,i-1];
            gg[j,i]:=gg[j,i-1];
          end
        else
          begin
            ma[j,i]:=ma[fa[j,i-1],i-1];
            gg[j,i]:=gg[fa[j,i-1],i-1];
          end;
      end;
  min:=maxlongint;
  for i:=1 to k do
    begin
      readln(u,v,t);
      if not kk then
        sum:=ans-faa(u,v)+t
      else
        if find(u)<>find(v) then
          sum:=ans+t
        else continue;
      if sum<min then
        begin
          min:=sum;
          zz:=bh;
          tt:=i;
        end;
    end;
  writeln(min);
  for i:=1 to s do
    if g[i]<>zz then writeln(g[i]);
  writeln(tt);
  close(input);close(output);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值