您的位置:首页 > 其它

【NOIP2013模拟】Freda的传呼机

2016-05-25 19:09 295 查看

【NOIP2013模拟】Freda的传呼机

Time Limits: 100 ms Memory Limits: 131072 KB

Description

为了 随时 与 rainbow快速交流, Freda制造了 两部传呼机 。Freda和 rainbow所在的地方有N座房屋、M条双向 光缆 。每条光缆连接两座房屋, 传呼机发出的信号只能沿着光缆传递,并且 传呼机的信号 从光缆的其中一端传递到另需要花费 t单位时间 。现在 Freda要 进行 Q次试验, 每次选取两座房屋,并想知道 传呼机的信号在这两座房屋之间传递 至少需 要多长时间。 Freda 和 rainbow简直弱爆了有木有T_TT_T ,请你帮他们吧……

N座房屋 通过光缆 一定是连通的, 并且这 M条光缆有以下三类连接情况:

A:光缆不形成环 ,也就是光缆仅 有 N-1条。

B:光缆只 形成一个环,也就是光缆 仅有 N条。

C:每条光缆仅在一个环中。

Input

第一行 包含三个用空格隔开的整数, N、M和 Q。

接下来 M行每三个整数 x、y、t,表示 房屋 x和 y之间有一条传递时为 t的光缆 。

最后 Q行每两个整数 x、y,表示 Freda想知道 在 x和 y之间传呼最少需要多长时间。

Output

输出 Q行,每一个整数表示 Freda每次试验的结果 。

Sample Input

Input1:

5 4 2

1 2 1

1 3 1

2 4 1

2 5 1

3 5

2 1

Input2:

5 5 2

1 2 1

2 1 1

1 3 1

2 4 1

2 5 1

3 5

2 1

Input3:

9 10 2

1 2 1

1 4 1

3 4 1

2 3 1

3 7 1

7 8 2

7 9 2

1 5 3

1 6 4

5 6 1

1 9

5 7

Sample Output

Output1:

3

1

Output2:

3

1

Output3:

5

6

Data Constraint

送分数据占10%,2<=N<=1000,N-1<=M<=1200。

A类数据占30%,M=N-1。

B类数据占50%,M=N。

C类数据占10%,M>N。

对于100%的数据,2<=N<=10000,N-1<=M<=12000,Q=10000,1<=x,y<=N,1<=t<=32768。

题目大意

给你一个图,图上每一条边最多只能在一个环中,给出Q组询问,每组询问是x,y,答x到y的最短距离

解题思路

业界毒瘤?仙人掌?不懂,总之讲一讲我的方法吧:

方法就是lca,可以将每个环看作一个节点,也就是说,除了环顶之外,其余环中的看作一点,那么我们就可以求出fa[x] (环顶或者父亲节点)和 di[x] (这个点到父亲节点的距离或到环顶的两条距离中,最小值)

我们可以首先用dfs找fa,di,标记光缆编号。

然后再一次dfs找出节点所在的层

最后lca一遍。

Codes

const
maxn=19231; maxx=83721;
var dis,s,p,first,last,f,owner,floor:array[0..10000]of longint;
fa,di:array[0..10000,0..16]of longint;
hush:array[0..maxn,1..3]of longint;
n,m,i,x,y,t,q,tot,j,top,z:longint;
a:array[0..24000,1..4]of longint;
bz,pd:array[0..12000]of boolean;
stack:array[0..10000,1..2]of longint;
function ha(x,y:longint):longint; //哈希求每条光缆的编号
var z:longint;
begin
z:=((x*maxx)+(y*y*2-1))mod maxn;
while (hush[z,3]<>0)and((hush[z,1]<>x)or(hush[z,2]<>y)) do z:=z mod maxn+1;
exit(z);
end;
procedure insert(w,x,y,z:longint); //插入边集数组
begin
a[w,1]:=x; a[w,2]:=y; a[w,3]:=z; a[w,4]:=w;
if first[x]=0 then first[x]:=w else a[last[x],4]:=w;
last[x]:=w;
end;
function turn(x:longint):longint;
begin
if x>m then x:=x-m;
exit(x);
end;
function min(p,q:longint):longint;
begin
if p<q then exit(p) else exit(q);
end;
procedure build(x,v,n,last:longint);  //找环,做fa,di
var o,y,t:longint;
begin
if f[x]<>0 then   //找到一个环
begin
inc(tot);
dis[tot]:=v-stack[f[x],2];
for o:=f[x]+1 to n-1 do
begin
y:=stack[o,1];
pd[y]:=true;
s[y]:=stack[o,2]-stack[f[x],2];
p[y]:=dis[tot]-s[y];
fa[y,0]:=x; di[y,0]:=min(s[y],p[y]);
owner[y]:=tot;  //一个点的归属环
end;
end else
begin
f[x]:=n;  //将每个节点存入栈中
stack[n,1]:=x;
stack[n,2]:=v;
o:=first[x];
while 1=1 do
begin
t:=turn(o);
if bz[t] then  //判断该边是否走过
begin
if o=a[o,4] then break;
o:=a[o,4];
continue;
end;
y:=a[o,2];
bz[t]:=true;
build(y,v+a[o,3],n+1,x);
if a[o,4]=o then break;
o:=a[o,4];
end;
if not pd[x] then  //处理不是环的情况
begin
inc(tot);
owner[x]:=tot;
fa[x,0]:=last;
di[x,0]:=stack[n,2]-stack[n-1,2];
end;
end;
end;
procedure find(x,t:longint);  //求每个点的层数
var o,y:longint;
begin
o:=first[x];
floor[x]:=t;
bz[x]:=true;
while 1=1 do
begin
y:=a[o,2];
if bz[y] then
begin
if a[o,4]=o then break;
o:=a[o,4];
continue;
end;
if owner[y]<>owner[x] then find(y,t+1) else find(y,t);
if a[o,4]=o then break;
o:=a[o,4];
end;
end;
function min(x,y,z:longint):longint;
begin
if x>y then x:=y;
if x>z then x:=z;
exit(x);
end;
procedure swap(var a,b:longint);
var c:longint;
begin
c:=a; a:=b; b:=c;
end;
function ask(x,y:longint):longint;  //求两点的最短路径
var dis,o:longint;
begin
if floor[x]>floor[y] then swap(x,y);
dis:=0;
for o:=16 downto 0 do
if 1<<o<=floor[y]-floor[x] then
begin
inc(dis,di[y,o]);
y:=fa[y,o];
end;
for o:=16 downto 0 do
begin
if fa[x,o]<>fa[y,o] then
begin
inc(dis,di[x,o]+di[y,o]);
x:=fa[x,o]; y:=fa[y,o];
end;
end;
if owner[x]=owner[y] then exit(dis+min(abs(s[x]-s[y]),s[x]+p[y],p[x]+s[y])) else exit(dis+di[x,0]+di[y,0]);
end;
begin
assign(input,'pager.in'); reset(input);
assign(output,'pager.out'); rewrite(output);
read(n,m,q);
for i:=1 to m do
begin
read(x,y,z);
if x>y then swap(x,y);
t:=ha(x,y);
if hush[t,3]<>0 then  //将两点之间的所有直接到达的路求最小值
begin
t:=hush[t,3];
a[t,3]:=min(a[t,3],z);
a[t+m,3]:=min(a[t+m,3],z);
end else
begin
inc(top);
hush[t,1]:=x; hush[t,2]:=y; hush[t,3]:=top;
insert(top,x,y,z);
insert(top+m,y,x,z);
end;
end;
build(1,0,1,0);
for j:=1 to 16 do  //搞lca
for i:=1 to n do
begin
fa[i,j]:=fa[fa[i,j-1],j-1];
di[i,j]:=di[i,j-1]+di[fa[i,j-1],j-1];
end;
fillchar(bz,sizeof(bz),false);
find(1,1);
for i:=1 to q do
begin
read(x,y);
writeln(ask(x,y));
end;
close(output); close(input);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: