Description

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

样例输入1
5 4 2
1 2 1
1 3 1
2 4 1
2 5 1
3 5
2 1

样例输入2
5 5 2
1 2 1
2 1 1
1 3 1
2 4 1
2 5 1
3 5
2 1

样例输入3
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

样例输出1
3
1

样例输出2
3
1

样例输出3
5
6

HINT

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

题解:

其实这三种情况都是仙人掌。。。

先重新建图,将原图中的一个点双(其实就是环)缩成一个点,如果一个点属于多个点双,则这个点向每个点双连条边,还有原图的桥边也要在新图里

由于这是仙人掌,得到的新图一定是个树,然后就想树上的最短路一样的求lca

不过要分清况讨论只有一个点是lca,两个点都是lca,两个点都不是lca,lca是环还是点等等,反正比较复杂

(感觉还是没讲清,看代码吧。。。)

code:

 #include<cstdio>
#include<iostream>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
#define maxn 20005
#define maxm maxn<<2
#define mod 236897
using namespace std;
typedef long long int64;
char ch;
bool ok;
void read(int &x){
for (ok=,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=;
for (x=;isdigit(ch);x=x*+ch-'',ch=getchar());
if (ok) x=-x;
}
int n,m,q,a,b,c;
int idx,dfn[maxn],low[maxn];
int top,cnt,bnm[maxn],tmp[maxn];
struct Stack{
int id,val;
}stack[maxn];
struct Point{
vector<int> bel,pos;
int siz;
void init(int a,int b){siz++,bel.push_back(a),pos.push_back(b);}
}point[maxn];
struct SCC{
vector<int> id,dis;
int siz,len,head;
void add(int v,int d){siz++,id.push_back(v),dis.push_back(d);}
int query(int a,int b){
int tmp=abs(dis[a]-dis[b]);
return min(tmp,len-tmp);
}
}scc[maxn];
int fa[maxn][],dep[maxn],dis[maxn];
struct Hash{
int tot,key[mod],pre[maxn],ans[maxn];
int64 val[maxn];
void add(int a,int b,int id){
int64 t=1LL*a*maxn+b;
int u=t%mod;
for (int p=key[u];p;p=pre[p]) if (val[p]==t) return;
pre[++tot]=key[u],key[u]=tot,ans[tot]=id,val[tot]=t;
}
int find(int a,int b){
int64 t=1LL*a*maxn+b;
int u=t%mod;
for (int p=key[u];p;p=pre[p]) if (val[p]==t) return ans[p];
return -;
}
}hash;
int num;
struct Edge{
int a,b,c;
}edge[maxm];
struct Graph{
int tot,now[maxn],son[maxm],pre[maxm],val[maxm];
void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
void add(int a,int b,int c){put(a,b,c),put(b,a,c);}
void dfs(int u,int fa,int va){
dfn[u]=low[u]=++idx,stack[++top]=(Stack){u,va};
for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if (!dfn[v]) dfs(v,u,val[p]),low[u]=min(low[u],low[v]);
else if (v!=fa) tmp[u]=val[p],low[u]=min(low[u],dfn[v]);
if (dfn[u]==low[u]){
top--;
if (fa) bnm[u]++,bnm[fa]++,edge[++num]=(Edge){fa,u,va};
}
if (low[u]==dfn[fa]){
int v,va,d=,id=,first=stack[top].id; ++cnt;
do{
v=stack[top].id,va=stack[top].val,top--;
point[v].init(cnt,id++),scc[cnt].add(v,d),d+=va;
}while (v!=u);
point[fa].init(cnt,id++),scc[cnt].add(fa,d),scc[cnt].len=d+tmp[first];
}
}
void dfs1(int u){
for (int i=;fa[u][i];i++) fa[u][i+]=fa[fa[u][i]][i];
if (u>n){
int idx=u-n;
if (fa[u][]) scc[idx].head=hash.find(fa[u][],idx);
for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if (v!=fa[u][]){
fa[v][]=u,dep[v]=dep[u]+;
dis[v]=dis[u]+scc[idx].query(scc[idx].head,hash.find(v,idx)),dfs1(v);
}
}
else for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if (v!=fa[u][]) fa[v][]=u,dep[v]=dep[u]+,dis[v]=dis[u]+val[p],dfs1(v);
}
}G1,G2;
void swim(int &u,int h){for (int i=;h;i--) if (h>=(<<i)) h-=(<<i),u=fa[u][i];}
int get_lca(int u,int v){
if (dep[u]<dep[v]) swap(u,v);
swim(u,dep[u]-dep[v]);
if (u==v) return u;
for (int i=;i>=;i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return fa[u][];
}
int get(int u){
if (!point[u].siz) return u;
return point[u].bel[]+n;
}
void query(int a,int b){
int ans=;
int ta=get(a),tb=get(b);
int lca=get_lca(ta,tb);
if (tb==lca) swap(ta,tb),swap(a,b);
if (ta==lca){
if (tb==lca){
if (lca>n){
int ida=hash.find(a,lca-n),idb=hash.find(b,lca-n);
printf("%d\n",scc[lca-n].query(ida,idb));
}
else puts("");
}
else{
if (tb>n) ans+=scc[tb-n].query(scc[tb-n].head,point[b].pos[]),b=tb;
if (lca>n){
swim(tb,dep[tb]-dep[lca]-);
int ida=hash.find(a,lca-n),idb=hash.find(tb,lca-n);
printf("%d\n",ans+dis[b]-dis[tb]+scc[lca-n].query(ida,idb));
}
else printf("%d\n",ans+dis[tb]-dis[lca]);
}
}
else{
if (ta>n) ans+=scc[ta-n].query(scc[ta-n].head,point[a].pos[]),a=ta;
if (tb>n) ans+=scc[tb-n].query(scc[tb-n].head,point[b].pos[]),b=tb;
if (lca>n){
swim(ta,dep[ta]-dep[lca]-),swim(tb,dep[tb]-dep[lca]-);
int ida=hash.find(ta,lca-n),idb=hash.find(tb,lca-n);
printf("%d\n",ans+dis[a]-dis[ta]+dis[b]-dis[tb]+scc[lca-n].query(ida,idb));
}
else printf("%d\n",ans+dis[a]+dis[b]-(dis[lca]<<));
}
}
int main(){
read(n),read(m),read(q);
for (int i=;i<=m;i++) read(a),read(b),read(c),G1.add(a,b,c);
for (int i=;i<=n;i++) if (!dfn[i]) G1.dfs(i,,);
for (int i=;i<=num;i++) G2.add(edge[i].a,edge[i].b,edge[i].c);
for (int u=;u<=n;u++) if (bnm[u]+point[u].siz>=)
for (int i=;i<point[u].siz;i++) G2.add(u,n+point[u].bel[i],);
for (int u=;u<=n;u++) for (int i=;i<point[u].siz;i++) hash.add(u,point[u].bel[i],point[u].pos[i]);
int root=cnt?n+:;
G2.dfs1(root);
while (q--) read(a),read(b),query(a,b);
return ;
}

bzoj3047: Freda的传呼机 && 2125: 最短路的更多相关文章

  1. bzoj3047:Freda的传呼机&&bzoj2125: 最短路

    完结撒花!!!!!!!!!!! 最后一题填坑1A仙人掌WWWWWWW我真流弊 首先把环拆开,环中每一个点连向环的根,然后搞LCA,答案就是套路的d[x]+d[y]-d[lca]*2 然后就可以发现,其 ...

  2. BZOJ 2125: 最短路

    2125: 最短路 Time Limit: 1 Sec  Memory Limit: 259 MBSubmit: 756  Solved: 331[Submit][Status][Discuss] D ...

  3. bzoj 1023: [SHOI2008]cactus仙人掌图 2125: 最短路 4728: 挪威的森林 静态仙人掌上路径长度的维护系列

    %%% http://immortalco.blog.uoj.ac/blog/1955 一个通用的写法是建树,对每个环建一个新点,去掉环上的边,原先环上每个点到新点连边,边权为点到环根的最短/长路长度 ...

  4. bzoj 2125 最短路——仙人掌两点间最短路

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2125 因为看了TJ又抄了标程,现在感觉还是轻飘飘的……必须再做一遍. 两点间的情况: 1.直 ...

  5. 【刷题】BZOJ 2125 最短路

    Description 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. Input 输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个 ...

  6. BZOJ.2125.最短路(仙人掌 最短路Dijkstra)

    题目链接 多次询问求仙人掌上两点间的最短路径. 如果是在树上,那么求LCA就可以了. 先做着,看看能不能把它弄成树. 把仙人掌看作一个图(实际上就是),求一遍根节点到每个点的最短路dis[i]. 对于 ...

  7. 【BZOJ】2125: 最短路 圆方树(静态仙人掌)

    [题意]给定带边权仙人掌图,Q次询问两点间最短距离.n,m,Q<=10000 [算法]圆方树处理仙人掌问题 [题解]树上的两点间最短路问题,常用倍增求LCA解决,考虑扩展到仙人掌图. 先对仙人掌 ...

  8. bzoj 2125 最短路 点双 圆方树

    LINK:最短路 一张仙人掌图 求图中两点最短路. \(n<=10000,Q<=10000,w>=1\) 考虑边数是多少 m>=n-1 对于一张仙人掌图 考虑先构建出来dfs树 ...

  9. BZOJ.2125.最短路(仙人掌 圆方树)

    题目链接 圆方树.做题思路不写了.. 就是当LCA是方点时跳进那个环可以分类讨论一下用树剖而不必须用倍增: 如果v是u的(唯一的那个)重儿子,那么u的DFS序上+1的点即是要找的:否则v会引出一条新的 ...

随机推荐

  1. 高性能、高流量Java Web站点打造的22条建议

    @http://www.csdn.net/article/2013-12-20/2817861-22-recommendations-for-building-effective-high-traff ...

  2. winform DataGridView双击修改单元格的值 分类: DataGridView 2014-08-04 19:39 150人阅读 评论(0) 收藏

    定义全局变量 string abcmycode = "";//当前行自编号 bool tf = false;//是否双击 //双击可编辑         private void ...

  3. 【Android - 框架】之GreenDao的使用

    上一篇博客([Android - 框架]之ORMLite的使用)中介绍了ORMLite的基本使用,今天我们来研究以下GreenDao的使用. GreenDao和ORMLite一样,都是基于ORM(Ob ...

  4. java websockect

    https://github.com/TooTallNate/Java-WebSocket (websockect类库包) http://blog.openlg.net/index.php/archi ...

  5. 为Android GridView 设置行背景

    经常有这样的需求,你的功能图标要像一个个物品,摆放在书架上,像这样: 我的思路比较简单,重载GridView,在他绘制子视图前,先把背景绘制完成 1 2 3 4 5 6 7 8 9 10 11 12 ...

  6. 怎样让HTML5调用手机摄像头拍照——实践就是一切

    原文:怎样让HTML5调用手机摄像头拍照--实践就是一切 NanShan 小编将思路提供给了大家.学编程最重要的是实践,我这尽管有完好的代码,可是希望大家都能够自己写出属于自己的代码 HTML5 Th ...

  7. linux系统时间同步更新

    linux中的时钟分为系统时钟和硬件时钟.硬件时钟通过bioss进行设置,系统时钟通过linux kernel进行设置.当linux启动时,bioss会读取系统时钟的时钟设置.在linux中涉及时间设 ...

  8. HTML5移动开发中的input输入框类型

    HTML5规范引入了许多新的input输入框类型 在HTML5移动开发中,通过这些新的输入框类型来显示定制后的键盘布局,用户体验更好,更容易填写各种表单 本文中,实测手机为肾4S与米4 数字类型num ...

  9. 关于WINDOWS命令

    1. Windows netstat 查看端口.进程占用 netstat -aon —  显示全部进程 2. 查看进程命令 tasklist — 显示全部进程 taskkill — 关闭至少一个系统进 ...

  10. object转化为string

    package common; import java.util.ArrayList; import java.util.List; public class DataZh { public stat ...