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. C# Excel操作类

    /// 常用工具类——Excel操作类 /// <para> ------------------------------------------------</para> / ...

  2. 从m个数中取top n

    将题目具体一点,例如,从100个数中取出从大到小排前10的数 方法1:使用快速排序 因为快速排序一趟下来,小于K的数都在K的前面,大于K的数都在K的后面 如果,小于K的数有35个,大于K的数有64个 ...

  3. 关于python写GUI桌面应用的一些研究结果

    研究了一下python开发GUI桌面应用的解决方案,研究结果记录如下: EasyGui:控件极为简单,连个基本的grid.list组件都没有,不适合商用,甚至是普通的应用都不行,放弃! Tkinter ...

  4. Codeforces Round #387(div 2)

    A =w= B VOV C QoQ D 题意:贝尔兰冬天很冷,那么司机要换上冬天专用轮胎才能开车.假设冬天一共有n天,有一套冬天专用轮胎,仅能使用k天,这套轮胎不管什么温度都能用,而夏天用的轮胎只能在 ...

  5. Unity NGUI UILabel文字变色 及相关问题

    在同一个UILabel中可以有不同颜色的文字只需要添加BBCode标记[ff0000]Red Label[-],那么在这个标记之间的RedLabel 就会变成红色 注意: 1.文本最终显示的颜色=Co ...

  6. Python异常处理 分类: python Raspberry Pi 服务器搭建 2015-04-01 13:22 172人阅读 评论(0) 收藏

    一个程序要保持稳定运行必须要有异常处理,本文将简单介绍Python中的try-except..异常处理语句的使用. 该种异常处理语法的规则是: 执行try下的语句,如果引发异常,则执行过程会跳到第一个 ...

  7. unity3D与网页的交互

    由于项目需要,要求用unity来展示三维场景,并在三维中能够方便的查询数据库等.一开始尝试在unity中直接连接数据库,当时连的xml,然而每次发布成网页后都会出现路径找不到等问题,所以迫不得已采用了 ...

  8. IDL计算儒略日

    遥感数据还有一些文章中使用数据的时候,经常使用儒略日(Julian day),即计算该天是一年中的第几天.正好有时间,就用IDL写了段儿小代码,方便使用.   ;+   ; :Author: caoz ...

  9. MVVM之View和ViewModel的关联

    概要: 将所有的VM在加载到Application的Static Resource中,然后在View中用标签指定. 实现: 1)采用特性指定要添加到StaticResource中的对象 public  ...

  10. linux设置语言编码

    前段时间在服务器上安装了centos6.2版本,当初安装时语言选择英文.这本来也没有什么问题,直到前一段时间.我的同事发现部署的web项目中出现乱码情况.但中文作为参数进行传递到下一个页面的时候就乱码 ...