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. DataGridView 添加行 分类: DataGridView 2014-12-07 08:49 263人阅读 评论(0) 收藏

    说明: (1)dgvGoods 是DataGridView名 (2)index 是最大行索引 一. DataGridViewRow row = new DataGridViewRow(); int i ...

  2. 深入N皇后问题的两个最高效算法的详解 分类: C/C++ 2014-11-08 17:22 117人阅读 评论(0) 收藏

    N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行.同一列.同一斜线上的皇后都会自动攻击). 一. 求解N皇后问题是算法中回溯法应用的一个经典案例 回溯算 ...

  3. vim note(6)--vim的一个较全的介绍(转)

    vim的配置文件 ~/.vimrc       用户的默认配置文件 ~/.vim/plugin/   用户的默认脚本文件的存放文件夹 ~/.vim/ftplugin/ 用户的默认文件类型相关脚本文件的 ...

  4. 【ES6】Set和Map中的NaN

    在JavaScript中,有个有意思的的式子:NaN !== NaN.在Set中的元素的重复检查或者Map键的定位过程中,都是用的类似恒等的检查逻辑.该逻辑和恒等检查的主要区别就是:NaN等于自身.

  5. Android(java)学习笔记200:Android中View动画之 XML实现 和 代码实现

    1.Animation 动画类型 Android的animation由四种类型组成: XML中: alph 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动 ...

  6. xcode 6.4模拟器出现多个相同版本:OSX Yosemite 上安装xcode7 beta和xcode6.4

    错误现象是:我在OSX Yosemite上同时安装了Xcode 7Beta和Xcode 6.4,然后Xcode 6.4的模拟器出现了重复版本.截图如下: 解决方法是: 删除该路径下的所有文件:~/Li ...

  7. PL/SQL 触发器简介

    与公司同事交流了一下,得知触发器很少用.性能是一方面,主要是如果用太多触发器,可能到时你都不知道会有什么操作自动发生. 有些操作可以在程序中控制.例如在插入某个表时,写个log表的记录.这可以用触发器 ...

  8. CSS3条件判断——@supports/window.CSS.supports()(转)

    CSS3条件判断,听起来"不明觉厉",如果你对CSS稍为熟悉一点的话,你会发现CSS中的"@media"就是条件判断之一.是的,在CSS3的条件判断规范文档中包 ...

  9. Node中Exports与module.export的使用与区别

    最近在看<node开发实战详解>时有写疑问,所以自己就整理了一些资料.下面是node4.*的官方api文档(http://nodejs.cn/doc/node_4/modules.html ...

  10. c# 访问修饰符的访问权限

    1. 访问修饰符. 指定声明的类型和类型成员的可访问性. (1) public:是类型和类型成员的访问修饰符.公共访问是允许的最高访问级别.对访问公共成员没有限制. (2) private:是一个成员 ...