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. ecshop获取url_domain

    <?php function url_domain() { $curr = strpos($_SERVER['PHP_SELF'], '/') !== false ? preg_replace( ...

  2. 用ChooseALicense帮自己选一个开源license,然后用AddALicense给自己的github自动加上license文件

    在我之前的一篇博客里面介绍过tl;drLegal ——开源软件license的搜索引擎,可以很方便的查询各种license,并且给出了很简洁的解释.今天又发现了另外一个帮助你选择你的开源软件licen ...

  3. 用Autohotkey让powerpoint幻灯片一直播放

    有台电脑专门接了个大电视循环播放一个幻灯片,但是有时候会弹出一些对话框,比如windows要更新之类的,这样的话powerpoint就不是active的进城了,这样幻灯片就会停下来,还需要人去手动点一 ...

  4. ASP.NET常用导出Excel方法汇总

    本文转载:http://mattberseth.com/blog/2007/04/export_gridview_to_excel_1.html http://geekswithblogs.net/a ...

  5. strace使用详解(转) 分类: shell ubuntu 2014-11-27 17:48 134人阅读 评论(0) 收藏

    (一) strace 命令    用途:打印 STREAMS 跟踪消息. 语法:strace [ mid sid level ] ... 描述:没有参数的 strace 命令将所有的驱动程序和模块中的 ...

  6. android生成验证码bitmap

    不多说了,直接上代码,项目中用到的,未做优化,还有很多参数未设置. [java] view plaincopy 1.import java.util.Random; 2. 3.import andro ...

  7. android 31 GridView

    GridView:网格列表,也支持适配器. package com.sxt.day05_01; import java.util.ArrayList; import java.util.List; i ...

  8. linux 管道--转

    linux 管道 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别. ...

  9. iOS-系统定位功能

    ios系统定位 前期准备 系统定位功能,需要用到框架:CoreLocation/CoreLocation.h, 然后导入文件#import <CoreLocation/CoreLocation. ...

  10. apache配置php

    第一部分:安装apache 1 .安装apache软件,custom 选全部,安装目录为: F:\Apache2.2\ 2.默认为80端口(如冲突,要学会修改端口) 输入:http://localho ...