[NOIP2013]货车运输

  • 时间限制: 1 s
  • 空间限制: 128000 KB
  • 题目等级 : 钻石 Diamond.

题目描述 Description
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入描述 Input Description
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

输出描述 Output Description
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

样例输入 Sample Input
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3

样例输出 Sample Output
3
-1
3

数据范围及提示 Data Size & Hint
对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;
对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;
对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

kruskal最大生成树+倍增
【code】

program cx;
uses math;
var i,m,n,sa,tg,treenum,cnt,qq,t:longint;
    home,ax,ay,aw,gym,head,next,e,w,h:array[0..100000]of longint;
    q:array[0..1000000]of longint;
    v:array[0..100000]of boolean;
    f,g:array[0..10000,0..20]of longint;

function find(x:longint):longint;
begin
  if home[x]=x then exit(x);
  home[x]:=find(home[x]);
  exit(home[x]);
end;

procedure link(x,y,z:longint);
begin
  inc(cnt); e[cnt]:=y; w[cnt]:=z;
  next[cnt]:=head[x]; head[x]:=cnt;
end;

procedure sort(l,r: longint);
var i,j,x,y: longint;
begin
  i:=l; j:=r;
  x:=aw[(l+r) >>1];
  repeat
    while aw[i]<x do inc(i);
    while x<aw[j] do dec(j);
    if not(i>j) then
      begin
        y:=aw[i]; aw[i]:=aw[j]; aw[j]:=y;
        y:=ax[i]; ax[i]:=ax[j]; ax[j]:=y;
        y:=ay[i]; ay[i]:=ay[j]; ay[j]:=y;
        inc(i); j:=j-1;
      end;
  until i>j;
  if l<j then sort(l,j);
  if i<r then sort(i,r);
end;

procedure kruskal;
var i,tot:longint;
begin
  fillchar(v,sizeof(v),0);
  for i:=1 to n do
    if not v[find(i)] then
      begin inc(treenum); v[find(i)]:=true; end;
  for i:=1 to n do home[i]:=i;
  sort(1,m);
  tot:=0;
  for i:=m downto 1 do
    begin
      if find(ax[i])=find(ay[i]) then continue;
      home[find(ax[i])]:=find(ay[i]);
      link(ax[i],ay[i],aw[i]);
      link(ay[i],ax[i],aw[i]);
      inc(tot);
      if tot=n-treenum then break;
    end;
end;

procedure dfs(x:longint);
var i,t:longint;
begin
  v[x]:=true;
  for i:=1 to 17 do
    begin
      if h[x]<(1<<i) then break;
      f[x,i]:=f[f[x,i-1],i-1];
      g[x,i]:=min(g[x,i-1],g[f[x,i-1],i-1]);
    end;
  t:=head[x];
  while t>0 do
    begin
      if not v[e[t]] then
        begin
          f[e[t],0]:=x;
          g[e[t],0]:=w[t];
          h[e[t]]:=h[x]+1;
          dfs(e[t]);
        end;
      t:=next[t];
    end;
end;

function lca(x,y:longint):longint;
var i,t:longint;
begin
  if h[x]<h[y] then begin t:=x; x:=y; y:=t; end;
  t:=h[x]-h[y];
  for i:=0 to 17 do
    if not (((1<<i) and t)=0) then
      x:=f[x,i];
  if x=y then exit(x);
  for i:=17 downto 0 do
    if f[x,i]<>f[y,i] then
      begin x:=f[x,i]; y:=f[y,i]; end;
  if x=y then exit(x);
  exit(f[x,0]);
end;

function ask(x,y:longint):longint;
var i,hk,t:longint;
begin
  hk:=maxlongint;
  t:=h[x]-h[y];
  for i:=0 to 17 do
    if not ((1<<i)and t=0) then
      begin
        hk:=min(hk,g[x,i]);
        x:=f[x,i];
      end;
  exit(hk);
end;

begin
  ASSIGN(INPUT, 'truck.in'); RESET(INPUT);
  ASSIGN(OUTPUT,'truck.out');REWRITE(OUTPUT);
  read(n,m);
  for i:=1 to n do home[i]:=i;
  for i:=1 to m do
    begin
      read(ax[i],ay[i],aw[i]);
      home[find(ax[i])]:=find(ay[i]);
    end;
  kruskal;

  fillchar(v,sizeof(v),0);
  for i:=1 to n do
    if not v[i] then dfs(i);
  read(qq);
  for i:=1 to qq do
    begin
      read(sa,tg);
      if find(sa)<>find(tg) then writeln(-1)
        else begin
               t:=lca(sa,tg);
               writeln(min(ask(sa,t),ask(tg,t)));
             end;
    end;
  CLOSE(INPUT);
  CLOSE(OUTPUT);
end.

你可能感兴趣的:(kruskal,LCA,noip)