【NOIP2013模拟】Freda的传呼机
2016-05-25 19:09
295 查看
【NOIP2013模拟】Freda的传呼机
Time Limits: 100 ms Memory Limits: 131072 KBDescription
为了 随时 与 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.
相关文章推荐
- 专家的修炼之路 —— 德雷福斯模型
- 北京海淀驾校学车经验
- 二进制(1):无符号编码和补码编码
- 用java来创建链表
- 超越学XML与DTD技术总结笔记(之三)
- 正则表达式基本语法
- Ruby编写HTML脚本替换小程序的实例分享
- centos 安装mount
- 【bzoj4551】[Tjoi2016&Heoi2016]树
- 开源的人工智能项目 Torch 和 FacebookAI 工具
- 【GDOI2014模拟】雨天的尾巴
- CSS布局自适应等分比例实践
- 超越学XML与DTD技术总结笔记(之二)
- Android Studio不打印Logcat解决!
- 原创:C++实现的可排序的双向链表
- uva 11584 划分成回文串
- 学习SpringMVC(二十)之返回JSON
- 超越学XML&DTD笔记技术总结(之一)
- 仿淘宝登录页EditText 的监听
- 多态的三个必要条件