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. Qt 智能指针学习(7种指针)

    Qt 智能指针学习 转载自:http://blog.csdn.net/dbzhang800/article/details/6403285 从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ ...

  2. 经典SQL语句大全之基础

    一.基础 1.说明:创建数据库CREATE DATABASE database-name 2.说明:删除数据库drop database dbname 3.说明:备份sql server--- 创建 ...

  3. [RxJS] Filtering operators: distinct and distinctUntilChanged

    Operator distinct() and its variants are an important type of Filtering operator. This lessons shows ...

  4. Java多线程,哲学家就餐问题

    问题描述:一圆桌前坐着5位哲学家,两个人中间有一只筷子,桌子中央有面条.哲学家思考问题,当饿了的时候拿起左右两只筷子吃饭,必须拿到两只筷子才能吃饭.上述问题会产生死锁的情况,当5个哲学家都拿起自己右手 ...

  5. web.xml常用标签整理(不定期更新)

    <?xml version="1.0" encoding="UTF-8"?><!-- 标明使用的XML版本和文档编码,此项必须位于第一行,之前 ...

  6. 基于HTML5的SLG游戏开发(一):搭建开发环境(1)

    开发环境: 1.操作系统:MacOS 10.8.5 2.本地web服务器:Apache 2.2.24 (Window环境推荐使用WampServer) 3.编码工具:WebStrom 7.0 4.调试 ...

  7. 关于text-align无法居中的问题

    昨天项目,一直出现一个无法居中的问题,最后发现竟然是text-align的问题,才发现自己对text-align的理解还是不够透彻,于是在此再举例分析下. css中的元素一共有三类:块元素.行内块和内 ...

  8. 《REWORK》启示录 招聘笔杆子——程序员为什么值得写博客

    Hire Great Writers 仿佛这是写给自己看的,不过这在其中也有着相当有趣的意义 .虽然自己算是一个能写的人,或许这算是一种不算才华的才华,写博文的意义通常不会在于去描述自己怎样,怎样.通 ...

  9. Oracle高版本导出dmp导入Oracle低版本报错:"不是有效的导出文件、头部验证失败"解决方法

    从Oracle高版本中导出dmp,然后导入到Oracle低版本时会报错:"不是有效的导出文件.头部验证失败",解决方法: 方法一:下载软件:AlxcTools,打开后选择要修改的文 ...

  10. 知识点摸清 - - position属性值之relative与absolute

    两者共同特点是: 改变文档流 激活元素left.top.right.bottom.z-index属性 让元素”浮起来“,z-index>0 不同的是: 1.position:relative 会 ...