【省选专题一】图论 51nod jzoj 4899 雪之国度 lca+倍增+并查集+最小生成树

13 篇文章 0 订阅
10 篇文章 0 订阅

Description
雪之国度有N座城市,依次编号为1到N,又有M条道路连接了其中的城市,每一条道路都连接了不同的2个城市,任何两座不同的城市之间可能不止一条道路。雪之女王赋予了每一座城市不同的能量,其中第i座城市被赋予的能量为Wi。
如果城市u和v之间有一条道路,那么只要此刻雪之女王的能量不小于|Wu-Wv|,这条道路就是安全的。如果城市u和v之间存在两条没有重复道路的安全路径(其中每一段道路都是安全的),则认为这两座城市之间有着良好的贸易关系。
最近,雪之女王因为情感问题,她的能量产生巨大的波动。为了维持雪之国度的经济贸易,她希望你能帮忙对Q对城市进行调查。对于第j对城市uj和vj,她希望知道在保证这两座城市之间有着良好贸易关系的前提之下,自己最少需要保持多少的能量。

Input

每一组数据第一行有3个整数,依次为N,M,Q,表示城市个数,道路个数,和所需要进行的调查次数。
之后一行,有N个整数,依次为每一个城市被赋予的能量Wi。
之后M行,每一行有2个整数,表示对应编号的两个城市之间有一条道路。
之后Q行,每一行有2个整数,表示一组调查的城市目标。
(保证图联通!)

Output

输出一共有Q行,依次对应Q次调查的结果。其中第j行给出了第j次调查的结果,即雪之女王需要保持的最少能量值。如果永远也无法做到,输出”infinitely”。

Sample Input

7 8 4
3 2 4 1 3 5 9
1 2
1 3
2 4
2 5
3 6
6 7
4 6
5 6
4 5
4 6
5 6
2 7

Sample Output

4
4
2
infinitely

Data Constraint

对于20%的数据来说,3<=N<=10, 3<=M<=20, 1<=Q<=10
对于另30%的数据来说,Wi=0
对于100%的数据来说,3<=N<=100000, 3<=M<=500000, 1<=Q<=100000, 每一座城市的能量Wi满足0<=Wi<=200000.

分析:先跑一个最小生成树,此时两点已经有一条路径。然后对于不在最小生成树上的边按从小到大的顺序加入,每加入一条x到y的边,就把x到y路径上的全部点缩成一个点,形成新树,这个点的权就是加入这条边的权。把缩的点连成一棵树(并查集可以看作是把多棵子树合并),答案就是belong[x]到belong[y]上点的最大值。

代码:

const
 maxn=100001;
 maxv=500001;

type
 code=record
  x,y,w:longint;
 end;
 node=record
  y,next:longint;
 end;

var
 n,m,test,o,k,e,ans:longint;
 belong,ls,dep,fa,c,p:array [0..maxn] of longint;
 bg,v:array [0..maxv] of boolean;
 g:array [0..maxv] of code;
 a:array [0..maxv] of longint;
 adge:array [0..maxv] of node;
 f,h:array [0..maxn,0..20] of longint;

procedure qsort(l,r:longint);
  var
    i,j,key:longint;
    temp:code;
  begin
    if l>=r then exit;
    i:=l;j:=r;
    key:=g[l+random(r-l+1)].w;
    repeat
      while  (g[i].w<key) do inc(i);
      while  (g[j].w>key) do dec(j);
      if i<=j then
      begin
        temp:=g[i];g[i]:=g[j];g[j]:=temp;
        inc(i);dec(j);
      end;
    until i>j;
    qsort(l,j);
    qsort(i,r);
  end;

procedure add(x,y:longint);
 begin
  inc(o);
  adge[o].y:=y;
  adge[o].next:=ls[x];
  ls[x]:=o;
 end;

function find(x:longint):longint;
 var root,y,w:longint;
begin
 y:=x;
 while p[y]>0 do
  y:=p[y];
 root:=y;
 y:=x;
 while p[y]>0 do
  begin
   w:=p[y];
   p[y]:=root;
   y:=w;
  end;
 find:=root;
end;

procedure union(x,y:longint);
 var
  u,v:longint;
begin
 u:=find(x);
 v:=find(y);
 if u=v then exit;
 p[v]:=u;
end;

procedure build_mst;
 var i,sum:longint;
begin
 sum:=0;
 for i:=1 to m do
  begin
   if find(g[i].x)<>find(g[i].y) then
    begin
     bg[i]:=true;
     union(g[i].x,g[i].y);
     add(g[i].x,g[i].y);
     add(g[i].y,g[i].x);
     sum:=sum+1;
     if sum=n-1 then exit;
    end;
  end;
end;

procedure dfs(x,fat:longint;depp:longint);
 var t:longint;
begin
 dep[x]:=depp;
 fa[x]:=fat;
 t:=ls[x];
 while t>0 do
  with adge[t] do
   begin
    if v[y]=false then
     begin
      v[y]:=true;
      dfs(y,x,depp+1);
     end;
    t:=next;
   end;
end;

procedure init;
 var i,j:longint;
begin
 readln(n,m,test);
 for i:=1 to n do
  read(a[i]);
 for i:=1 to m do
  begin
   readln(g[i].x,g[i].y);
   g[i].w:=abs(a[g[i].x]-a[g[i].y]);
  end;
 qsort(1,m);
end;

procedure up(x,y,z:longint);
var s,t,i:longint;
    flag1,flag2:boolean;
 begin
  if find(x)=find(y) then exit;
  k:=0; e:=e+1;
  a[e]:=z;
  while x<>y do
   begin
    s:=find(x);
    t:=find(y);
    flag1:=false; flag2:=false;
    if s=x then begin s:=fa[x]; flag1:=true; end;
    if t=y then begin t:=fa[y]; flag2:=true; end;
    if dep[s]>=dep[t] then
     begin
      if flag1 then
       begin
        if belong[x]=0 then belong[x]:=e
                       else
                         begin
                          add(belong[x],e); add(e,belong[x]);
                         end;
        k:=k+1;
        c[k]:=x;
       end
      else
       begin
        add(belong[s],e);
        add(e,belong[s]);
       end;
      x:=s;
     end
    else
     begin
      if flag2 then
       begin
        if belong[y]=0 then belong[y]:=e
                       else begin
                        add(belong[y],e); add(e,belong[y]);
                       end;

        k:=k+1;
        c[k]:=y;
       end
      else
       begin
        add(belong[t],e);
        add(e,belong[t]);
       end;
      y:=t;
     end;
   end;
  if belong[x]=0 then begin belong[x]:=e; k:=k+1; c[k]:=x; end
  else
   begin
    add(belong[x],e);
    add(e,belong[x]);
   end;
  for i:=1 to k do
   union(x,c[i]);
 end;

function max(x,y:longint):longint;
 begin
  if x>y then exit(x)
         else exit(y);
 end;

procedure lca(x,y:longint);
var t,s:longint;
 begin
  ans:=max(a[x],a[y]);
  if dep[x]>dep[y] then
   begin
    x:=x xor y;
    y:=x xor y;
    x:=x xor y;
   end;
  s:=dep[y]-dep[x];
  t:=20;
  while t>=0 do
   begin
    if 1 shl t<=s then
     begin
      ans:=max(ans,h[y,t]);
      y:=f[y,t];
      s:=s-1 shl t;
     end;
    t:=t-1;
   end;
  if x=y then begin writeln(ans); exit; end;
  t:=20;
  while t>=0 do
   begin
    if f[x,t]<>f[y,t] then
     begin
      ans:=max(max(ans,h[x,t]),h[y,t]);
      x:=f[x,t];
      y:=f[y,t];
     end;
    t:=t-1;
   end;
  ans:=max(ans,a[fa[x]]);
  writeln(ans);
 end;

procedure main;
 var i,j,x,y:longint;
begin
 build_mst;
 fillchar(p,sizeof(p),0);
 v[1]:=true;
 dfs(1,0,1);
 o:=0;
 fillchar(ls,sizeof(ls),0);
 for i:=1 to m do
  if bg[i]=false then
   begin
    up(g[i].x,g[i].y,g[i].w);
   end;
 fillchar(v,sizeof(v),false);
 fillchar(dep,sizeof(dep),0);
 for i:=1 to e do
  begin
   if v[i]=false then
    begin
     v[i]:=true;
     dfs(i,0,1);
    end;
  end;
 for i:=1 to e do
  begin
   f[i,0]:=fa[i];
   h[i,0]:=a[fa[i]];
  end;
 for j:=1 to 20 do
  for i:=1 to e do
   begin
    f[i,j]:=f[f[i,j-1],j-1];
    h[i,j]:=max(h[i,j-1],h[f[i,j-1],j-1]);
   end;
 for i:=1 to test do
  begin
   readln(x,y);
   if find(x)<>find(y) then writeln('infinitely')
                       else lca(belong[x],belong[y]);

  end;
end;


begin
 assign(input,'city.in');
 assign(output,'city.out');
 reset(input);
 rewrite(output);
 init;
 main;
 close(input);
 close(output);
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值