一道生成树问题 poj2831

21 篇文章 0 订阅
9 篇文章 0 订阅

题目大意:给张图,然后问你,如果某边的权值下降为V,那么这个边有无可能在最小生成树中呢?节点数≤1000,边数≤100000,询问数≤100000。

由于网上唯一的标程是java,所以讲一下这道题。

可知,最小生成树上两点间路径上最大边为这两点间所有路径中路径上最大边最小的边,如果一条边可以出现在最小生成树中,其边权必小于等于两点间路径上最大边,于是我们只需快速找出这条边,即可回答。

又是一个结论这种边即两点在最小顺序生成树中的lca(郭华阳论文),所以求一遍最小生成树,在每次跑一边lca。

因为今天做了一道倍增题,所以这道题的lca我也是用倍增算法,先倍增到同一深度,在同时向上倍增,如果过了就减小倍数。




var lca,n,m,s1,q:longint;
    t,l,r,p,w,ww:array[1..300000]of longint;
    b,lson,rson:array[1..300000]of longint;
    f:array[1..300000,0..30]of longint;
    d,st:array[1..300000]of longint;
procedure qsort(ll,rr:longint);
var i,j,x,c:longint;
begin
 i:=ll;j:=rr;x:=w[(ll+rr)>>1];
 repeat
  while w[i]<x do inc(i);
  while x<w[j] do dec(j);
  if not(i>j) then begin
   c:=w[i];w[i]:=w[j];w[j]:=c;
   c:=l[i];l[i]:=l[j];l[j]:=c;
   c:=r[i];r[i]:=r[j];r[j]:=c;
   c:=p[i];p[i]:=p[j];p[j]:=c;
   inc(i);dec(j)
  end
 until i>j;
 if i<rr then qsort(i,rr);
 if ll<j then qsort(ll,j)
end;
procedure link(root,l,r:longint);
begin
 lson[root]:=l;rson[root]:=r;
 f[l,0]:=root;f[r,0]:=root
end;
procedure bfs(s:longint);
var h,r,ne:longint;
begin
 fillchar(st,sizeof(st),0);fillchar(d,sizeof(d),127);
 h:=0;r:=1;st[1]:=s;d[s]:=0;
 repeat
  inc(h);ne:=st[h];
  if lson[ne]<>0 then begin d[lson[ne]]:=d[ne]+1;inc(r);st[r]:=lson[ne] end;
  if rson[ne]<>0 then begin d[rson[ne]]:=d[ne]+1;inc(r);st[r]:=rson[ne] end
 until h>=r
end;
procedure origin;
var i,k:longint;
begin
  for k:=1 to 30 do
   for i:=1 to s1-1 do if d[i]>=1<<k then
     f[i,k]:=f[f[i,k-1],k-1]
end;
function ask(l,r:longint):longint;
var e,k,p,dis:longint;
begin
  if d[r]>d[l] then begin e:=l;l:=r;r:=e end;
  dis:=d[l]-d[r];p:=0;
  while dis<>0 do begin
    if dis and 1=1 then l:=f[l,p];
    inc(p);
    dis:=dis>>1
  end;
  k:=0;
  while l<>r do begin
    if (f[l,k]<>f[r,k])or((f[l,k]=f[r,k])and(k=0)) then begin
     l:=f[l,k];r:=f[r,k];inc(k)
    end
    else dec(k)
  end;
  ask:=ww[l]
end;
function find(x:longint):longint;
begin
 if b[x]<>x then b[x]:=find(b[x]);find:=b[x]
end;
procedure init;
var i,ll,rr,x,y,z:longint;
begin
  readln(n,m,q);
  for i:=1 to m do begin
    readln(x,y,z);
    l[i]:=x;r[i]:=y;w[i]:=z;
    p[i]:=i
  end;
  qsort(1,m);
  for i:=1 to n+m do b[i]:=i;
  s1:=n;
  fillchar(f,sizeof(f),0);
  for i:=1 to m do begin
   ll:=find(l[i]);rr:=find(r[i]);
   if ll<>rr then begin
    inc(s1);
    b[ll]:=s1;b[rr]:=s1;ww[s1]:=w[i];
    link(s1,ll,rr)
   end
  end;
  for i:=1 to m do t[p[i]]:=i;
  bfs(s1);
  origin;
  for i:=1 to q do begin
    readln(x,y);
    x:=t[x];
    lca:=ask(l[x],r[x]);
    if y<=lca then writeln('Yes') else writeln('No')
  end;
end;
begin
 init;
end.


updata:简写版

var lca,n,m,s1,q:longint;
    t,l,r,p,w,ww:array[1..300000]of longint;
    b,lson,rson:array[1..300000]of longint;
    f:array[1..300000,0..30]of longint;
    d,st:array[1..300000]of longint;
procedure qsort(ll,rr:longint);
var i,j,x,c:longint;
begin
 i:=ll;j:=rr;x:=w[(ll+rr)>>1];
 repeat
  while w[i]<x do inc(i);
  while x<w[j] do dec(j);
  if not(i>j) then begin
   c:=w[i];w[i]:=w[j];w[j]:=c;
   c:=l[i];l[i]:=l[j];l[j]:=c;
   c:=r[i];r[i]:=r[j];r[j]:=c;
   c:=p[i];p[i]:=p[j];p[j]:=c;
   inc(i);dec(j)
  end
 until i>j;
 if i<rr then qsort(i,rr);
 if ll<j then qsort(ll,j)
end;
procedure link(root,l,r:longint);
begin
 lson[root]:=l;rson[root]:=r;
 f[l,0]:=root;f[r,0]:=root
end;
procedure bfs(s:longint);
var h,r,ne:longint;
begin
 fillchar(st,sizeof(st),0);fillchar(d,sizeof(d),127);
 h:=0;r:=1;st[1]:=s;d[s]:=0;
 repeat
  inc(h);ne:=st[h];
  if lson[ne]<>0 then begin d[lson[ne]]:=d[ne]+1;inc(r);st[r]:=lson[ne] end;
  if rson[ne]<>0 then begin d[rson[ne]]:=d[ne]+1;inc(r);st[r]:=rson[ne] end
 until h>=r
end;
procedure origin;
var i,k:longint;
begin
  for k:=1 to 30 do
   for i:=1 to s1-1 do if d[i]>=1<<k then
     f[i,k]:=f[f[i,k-1],k-1]
end;
function ask(l,r:longint):longint;
var e,i,k,p,dis:longint;
begin
  if d[r]>d[l] then begin e:=l;l:=r;r:=e end;
  dis:=d[l]-d[r];p:=0;
  while dis<>0 do begin
    if dis and 1=1 then l:=f[l,p];
    inc(p);
    dis:=dis>>1
  end;
  k:=0;
  {while l<>r do begin
    if (f[l,k]<>f[r,k])or((f[l,k]=f[r,k])and(k=0)) then begin
     l:=f[l,k];r:=f[r,k];inc(k)
    end
    else dec(k)
  end;}
  for i:=30 downto 0 do
        if (f[l,i]<>f[r,i]) then begin
                l:=f[l,i];
                r:=f[r,i];
        end;
  l:=f[l,0];r:=f[r,0];
  ask:=ww[l]
end;
function find(x:longint):longint;
begin
 if b[x]<>x then b[x]:=find(b[x]);find:=b[x]
end;
procedure init;
var i,ll,rr,x,y,z:longint;
begin
  readln(n,m,q);
  for i:=1 to m do begin
    readln(x,y,z);
    l[i]:=x;r[i]:=y;w[i]:=z;
    p[i]:=i
  end;
  qsort(1,m);
  for i:=1 to n+m do b[i]:=i;
  s1:=n;
  fillchar(f,sizeof(f),0);
  for i:=1 to m do begin
   ll:=find(l[i]);rr:=find(r[i]);
   if ll<>rr then begin
    inc(s1);
    b[ll]:=s1;b[rr]:=s1;ww[s1]:=w[i];
    link(s1,ll,rr)
   end
  end;
  for i:=1 to m do t[p[i]]:=i;
  bfs(s1);
  origin;
  for i:=1 to q do begin
    readln(x,y);
    x:=t[x];
    lca:=ask(l[x],r[x]);
    if y<=lca then writeln('Yes') else writeln('No')
  end;
end;
begin
 init;
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值