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
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:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<vector> 5 #include<cstring> 6 #include<algorithm> 7 #define maxn 20005 8 #define maxm maxn<<2 9 #define mod 236897 10 using namespace std; 11 typedef long long int64; 12 char ch; 13 bool ok; 14 void read(int &x){ 15 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 16 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 17 if (ok) x=-x; 18 } 19 int n,m,q,a,b,c; 20 int idx,dfn[maxn],low[maxn]; 21 int top,cnt,bnm[maxn],tmp[maxn]; 22 struct Stack{ 23 int id,val; 24 }stack[maxn]; 25 struct Point{ 26 vector<int> bel,pos; 27 int siz; 28 void init(int a,int b){siz++,bel.push_back(a),pos.push_back(b);} 29 }point[maxn]; 30 struct SCC{ 31 vector<int> id,dis; 32 int siz,len,head; 33 void add(int v,int d){siz++,id.push_back(v),dis.push_back(d);} 34 int query(int a,int b){ 35 int tmp=abs(dis[a]-dis[b]); 36 return min(tmp,len-tmp); 37 } 38 }scc[maxn]; 39 int fa[maxn][15],dep[maxn],dis[maxn]; 40 struct Hash{ 41 int tot,key[mod],pre[maxn],ans[maxn]; 42 int64 val[maxn]; 43 void add(int a,int b,int id){ 44 int64 t=1LL*a*maxn+b; 45 int u=t%mod; 46 for (int p=key[u];p;p=pre[p]) if (val[p]==t) return; 47 pre[++tot]=key[u],key[u]=tot,ans[tot]=id,val[tot]=t; 48 } 49 int find(int a,int b){ 50 int64 t=1LL*a*maxn+b; 51 int u=t%mod; 52 for (int p=key[u];p;p=pre[p]) if (val[p]==t) return ans[p]; 53 return -1; 54 } 55 }hash; 56 int num; 57 struct Edge{ 58 int a,b,c; 59 }edge[maxm]; 60 struct Graph{ 61 int tot,now[maxn],son[maxm],pre[maxm],val[maxm]; 62 void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;} 63 void add(int a,int b,int c){put(a,b,c),put(b,a,c);} 64 void dfs(int u,int fa,int va){ 65 dfn[u]=low[u]=++idx,stack[++top]=(Stack){u,va}; 66 for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 67 if (!dfn[v]) dfs(v,u,val[p]),low[u]=min(low[u],low[v]); 68 else if (v!=fa) tmp[u]=val[p],low[u]=min(low[u],dfn[v]); 69 if (dfn[u]==low[u]){ 70 top--; 71 if (fa) bnm[u]++,bnm[fa]++,edge[++num]=(Edge){fa,u,va}; 72 } 73 if (low[u]==dfn[fa]){ 74 int v,va,d=0,id=0,first=stack[top].id; ++cnt; 75 do{ 76 v=stack[top].id,va=stack[top].val,top--; 77 point[v].init(cnt,id++),scc[cnt].add(v,d),d+=va; 78 }while (v!=u); 79 point[fa].init(cnt,id++),scc[cnt].add(fa,d),scc[cnt].len=d+tmp[first]; 80 } 81 } 82 void dfs1(int u){ 83 for (int i=0;fa[u][i];i++) fa[u][i+1]=fa[fa[u][i]][i]; 84 if (u>n){ 85 int idx=u-n; 86 if (fa[u][0]) scc[idx].head=hash.find(fa[u][0],idx); 87 for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 88 if (v!=fa[u][0]){ 89 fa[v][0]=u,dep[v]=dep[u]+1; 90 dis[v]=dis[u]+scc[idx].query(scc[idx].head,hash.find(v,idx)),dfs1(v); 91 } 92 } 93 else for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 94 if (v!=fa[u][0]) fa[v][0]=u,dep[v]=dep[u]+1,dis[v]=dis[u]+val[p],dfs1(v); 95 } 96 }G1,G2; 97 void swim(int &u,int h){for (int i=14;h;i--) if (h>=(1<<i)) h-=(1<<i),u=fa[u][i];} 98 int get_lca(int u,int v){ 99 if (dep[u]<dep[v]) swap(u,v); 100 swim(u,dep[u]-dep[v]); 101 if (u==v) return u; 102 for (int i=14;i>=0;i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; 103 return fa[u][0]; 104 } 105 int get(int u){ 106 if (!point[u].siz) return u; 107 return point[u].bel[0]+n; 108 } 109 void query(int a,int b){ 110 int ans=0; 111 int ta=get(a),tb=get(b); 112 int lca=get_lca(ta,tb); 113 if (tb==lca) swap(ta,tb),swap(a,b); 114 if (ta==lca){ 115 if (tb==lca){ 116 if (lca>n){ 117 int ida=hash.find(a,lca-n),idb=hash.find(b,lca-n); 118 printf("%d\n",scc[lca-n].query(ida,idb)); 119 } 120 else puts("0"); 121 } 122 else{ 123 if (tb>n) ans+=scc[tb-n].query(scc[tb-n].head,point[b].pos[0]),b=tb; 124 if (lca>n){ 125 swim(tb,dep[tb]-dep[lca]-1); 126 int ida=hash.find(a,lca-n),idb=hash.find(tb,lca-n); 127 printf("%d\n",ans+dis[b]-dis[tb]+scc[lca-n].query(ida,idb)); 128 } 129 else printf("%d\n",ans+dis[tb]-dis[lca]); 130 } 131 } 132 else{ 133 if (ta>n) ans+=scc[ta-n].query(scc[ta-n].head,point[a].pos[0]),a=ta; 134 if (tb>n) ans+=scc[tb-n].query(scc[tb-n].head,point[b].pos[0]),b=tb; 135 if (lca>n){ 136 swim(ta,dep[ta]-dep[lca]-1),swim(tb,dep[tb]-dep[lca]-1); 137 int ida=hash.find(ta,lca-n),idb=hash.find(tb,lca-n); 138 printf("%d\n",ans+dis[a]-dis[ta]+dis[b]-dis[tb]+scc[lca-n].query(ida,idb)); 139 } 140 else printf("%d\n",ans+dis[a]+dis[b]-(dis[lca]<<1)); 141 } 142 } 143 int main(){ 144 read(n),read(m),read(q); 145 for (int i=1;i<=m;i++) read(a),read(b),read(c),G1.add(a,b,c); 146 for (int i=1;i<=n;i++) if (!dfn[i]) G1.dfs(i,0,0); 147 for (int i=1;i<=num;i++) G2.add(edge[i].a,edge[i].b,edge[i].c); 148 for (int u=1;u<=n;u++) if (bnm[u]+point[u].siz>=2) 149 for (int i=0;i<point[u].siz;i++) G2.add(u,n+point[u].bel[i],0); 150 for (int u=1;u<=n;u++) for (int i=0;i<point[u].siz;i++) hash.add(u,point[u].bel[i],point[u].pos[i]); 151 int root=cnt?n+1:1; 152 G2.dfs1(root); 153 while (q--) read(a),read(b),query(a,b); 154 return 0; 155 }