Description
給一個N個點M條邊的連通無向圖,滿足每條邊最多屬于一個環,有Q組詢問,每次詢問兩點之間的最短路徑。
Input
輸入的第一行包含三個整數,分別表示N和M和Q 下接M行,每行三個整數v,u,w表示一條無向邊v-u,長度為w 最后Q行,每行兩個整數v,u表示一組詢問
Output
輸出Q行,每行一個整數表示詢問的答案
Sample Input
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
5
6
HINT
對于100%的數據,N<=10000,Q<=10000
這題寫的我真TM舒服……
首先對仙人掌建出一棵圓方樹,考慮樹上的邊權,如果是圓點連圓點,則邊權不變;如果是圓點連方點,則邊權為圓點到方點所屬環上,dfs序最小的點的距離
然后我們考慮lca的兩種情況,如果lca是圓點,那么我們直接輸出圓方樹上的兩點之間距離;如果lca是方點,我們找到\(x,y\)在lca兒子中的祖先節點\(x',y'\),則答案為\(dis_{x\rightarrow x'}+dis_{x'\rightarrow y'}+dis_{y'\rightarrow y}\)
(樹剖求lca找\(x',y'\)時細節賊難受……)
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Fi first
#define Se second
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef pair<int,int>pii;
typedef unsigned long long ull;
inline char gc(){static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){int x=0,f=1; char ch=gc();for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';return x*f;
}
inline int read(){int x=0,f=1; char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';return x*f;
}
inline void print(int x){if (x<0) putchar('-'),x=-x;if (x>9) print(x/10);putchar(x%10+'0');
}
const int N=1e4;
int V[N+10],cnt,n,m,q;
struct node{int lca,x,y;node(){lca=x=y=0;}node(int _l,int _x,int _y){lca=_l,x=_x,y=_y;}void insert(int _l,int _x,int _y){lca=_l,x=_x,y=_x;}
};
struct S1{ int pre[(N<<2)+10],now[(N<<1)+10],child[(N<<2)+10],val[(N<<2)+10],tot;int fa[(N<<1)+10],deep[(N<<1)+10],top[(N<<1)+10],Rem[(N<<1)+10],size[(N<<1)+10],dis[(N<<1)+10];void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}void dfs(int x){deep[x]=deep[fa[x]]+1,size[x]=1;for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa[x]) continue;fa[son]=x,dis[son]=dis[x]+val[p];dfs(son),size[x]+=size[son];if (size[Rem[x]]<size[son]) Rem[x]=son;}}void build(int x){if (!x) return;top[x]=Rem[fa[x]]==x?top[fa[x]]:x;build(Rem[x]);for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa[x]||son==Rem[x]) continue;build(son);}}node LCA(int x,int y){int lastx=0,lasty=0;while (top[x]!=top[y]){if (deep[top[x]]<deep[top[y]]) lasty=top[y],y=fa[top[y]];else lastx=top[x],x=fa[top[x]];}if (x==y) return node(x,lastx,lasty);if (deep[x]<deep[y]) return node(x,lastx,Rem[x]);else return node(y,Rem[y],lasty);//WA了好幾次,畫了圖才發現應該這樣寫……}
}RST;//Round Square Tree
struct S2{int pre[(N<<2)+10],now[N+10],child[(N<<2)+10],val[(N<<2)+10];int fa[N+10],dfn[N+10],low[N+10],fv[N+10],dis[N+10],stack[N+10],belong[N+10];bool instack[N+10];int tot,Time,top,num;void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}int distant(int x,int y,int pos){if (dfn[x]<dfn[y]) swap(x,y);return min(dis[x]-dis[y],V[pos]-(dis[x]-dis[y]));}void dfs(int x){dfn[x]=++Time;for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa[x]) continue;if (!dfn[son]){fa[son]=x,dis[son]=dis[x]+val[p];fv[son]=val[p],dfs(son);}else if (dfn[son]<dfn[x]){V[++cnt]=val[p],RST.insert(cnt+n,son,0);for (int i=x;i!=son;i=fa[i]) V[cnt]+=fv[i];for (int i=x;i!=son;i=fa[i]) RST.insert(cnt+n,i,distant(i,son,cnt));}}}void tarjan(int x,int fa){//不論如何枚舉順序都是一樣的,那么dfn就算再次dfs也是一樣的dfn[x]=low[x]=++Time;instack[stack[++top]=x]=1;for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa) continue;if (!dfn[son]) tarjan(son,x),low[x]=min(low[x],low[son]);else if (instack[son]) low[x]=min(low[x],dfn[son]);}if (dfn[x]==low[x]){belong[x]=++num;instack[x]=0;while (stack[top]!=x) belong[stack[top]]=num,instack[stack[top--]]=0;top--;}}void init(){Time=0;memset(dfn,0,sizeof(dfn));}
}OT;//Original Tree
struct S3{int x,y,z;void insert(int _x,int _y,int _z){x=_x,y=_y,z=_z;}
}Line[(N<<1)+10];
int main(){n=read(),m=read(),q=read();for (int i=1;i<=m;i++){int x=read(),y=read(),z=read();OT.insert(x,y,z);Line[i].insert(x,y,z);}OT.dfs(1),OT.init(),OT.tarjan(1,0);for (int i=1;i<=m;i++)if (OT.belong[Line[i].x]!=OT.belong[Line[i].y])RST.insert(Line[i].x,Line[i].y,Line[i].z);RST.dfs(1),RST.build(1);for (int i=1;i<=q;i++){int x=read(),y=read();node tmp=RST.LCA(x,y);if (tmp.lca<=n) printf("%d\n",RST.dis[x]+RST.dis[y]-2*RST.dis[tmp.lca]);else{int res=RST.dis[x]+RST.dis[y]-RST.dis[tmp.x]-RST.dis[tmp.y];res+=OT.distant(tmp.x,tmp.y,tmp.lca-n);printf("%d\n",res);}}return 0;
}