[Vijos P1843] Noip2013Day1T3

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

那么我们就先跑一个最大生成树对吧,然后找两点之间路径的最小值

找路径最小值什么的主要是用一个在线的LCA

在维护f数组同时我们再加入一个d数组,d[u,i]表示从u开始向上2^i步里的最小值

然后就可以了~

代码量什么的略大,我写了160行左右

const     shuru='truck.in';
	  shuchu='truck.out';
	  maxlen=13;
type edge=record
		from,too,wei:longint;
		  end;
var	deep,father,headlist:array[0..10001] of longint;
	next,weight,t:array[0..20001] of longint;
	a:array[0..50001] of edge;
	vis:array[0..10001] of boolean;
	d,f:array[0..10001,0..13] of longint;
	step,num,x,y,z,now,i,j,k,n,m,q:longint;
	p:edge;
function min(a,b:longint):longint;
begin
	if amid) do inc(i);
		while (a[j].weij;
	if j>l then qsort(l,j);
	if ifather[step]) do step:=father[step];
	while k<>step do
	begin
		x:=father[k];
		father[k]:=step;
		k:=x;
	end;
	exit(step);
end;
procedure merge(a,b:longint);
var fa1,fa2:longint;
begin
	fa1:=find(a); fa2:=find(b);
	father[fa2]:=fa1;
end;
procedure mit;
begin
	qsort(1,m);
	now:=1;
	for i:=1 to n-1 do
	begin
		x:=a[now].from; y:=a[now].too; z:=a[now].wei;
		while (find(x)=find(y)) do
		begin
			inc(now);
			if now>=m+1 then break;
			x:=a[now].from; y:=a[now].too; z:=a[now].wei;
		end;
		if now>=m+1 then break;
		merge(x,y);
		inc(num);
		next[num]:=headlist[x];
		headlist[x]:=num;
		weight[num]:=z;
		t[num]:=y;
		inc(num);
		next[num]:=headlist[y];
		headlist[y]:=num;
		weight[num]:=z;
		t[num]:=x;
	end;
end;
procedure dfs(u:longint);
var i:longint;
begin
	for i:=1 to maxlen do f[u,i]:=f[f[u,i-1],i-1];
	for i:=1 to maxlen do d[u,i]:=min(d[u,i-1],d[f[u,i-1],i-1]);
	i:=headlist[u];
	while i<>-1 do
	begin
		if (not(vis[t[i]])) then begin
									i:=next[i];
									continue;
								 end;
		vis[t[i]]:=false;
		f[t[i],0]:=u;
		d[t[i],0]:=weight[i];
		deep[t[i]]:=deep[u]+1;
		dfs(t[i]);
		i:=next[i];
	end;
end;
function ask(a,b:longint):longint;
var i,del:longint;
begin
	ask:=maxlongint;
	if deep[a]>deep[b] then begin
								step:=a;
								a:=b;
								b:=step;
							end;
	del:=deep[b]-deep[a];
	for i:=0 to maxlen do if (del and (1 shl i))<>0 then begin
															ask:=min(d[b,i],ask);
															b:=f[b,i];
														 end;
	if a<>b then begin
		for i:=maxlen downto 0 do
			if f[a,i]<>f[b,i] then begin
										ask:=min(ask,d[b,i]);
										ask:=min(ask,d[a,i]);
										a:=f[a,i];
										b:=f[b,i];
								   end;
		ask:=min(ask,d[a,0]);
		ask:=min(ask,d[b,0]);
				end;
end;
procedure main;
begin
	init;
	mit;
	fillchar(vis,sizeof(vis),true);
	for i:=1 to n do
		if vis[i] then begin
						deep[i]:=1;
                                                vis[i]:=false;
						dfs(i);
					   end;
	readln(q);
	for i:=1 to q do
	begin
		readln(x,y);
		if find(x)<>find(y) then writeln(-1)
							else writeln(ask(x,y));
	end;
	close(input);
	close(output);
end;
begin
	main;
end.


你可能感兴趣的:(LCA,2014,倍增,Vijos)