• [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.
  • 相关阅读:
    DS博客作业05--查找
    DS博客作业04--图
    DS博客作业03--树
    DS博客作业02--栈和队列
    DS01-线性表
    C博客作业06-结构体&文件
    C博客作业05--指针
    C博客作业04--数组
    C博客作业03--函数
    C博客作业02--循环结构
  • 原文地址:https://www.cnblogs.com/cww97/p/7534045.html
Copyright © 2020-2023  润新知