題解:
首先如果這是一棵樹的話,那麼我們只需要選定乙個根,之後掃一遍這棵樹,詢問的話即是兩點到根節點的距離之和減去二倍的兩點lca到根節點距離。
那麼如果是一棵仙人掌的話,我們強行套用這個辦法,重新構造一棵樹。
對於仙人掌中的乙個環來說,我們把該環中深度最小的點當做這個環的根,然後環上其他點連向該環,非環上邊正常連線。
這個樹有什麼優越性呢?
不妨假定1為根,那麼每個點到1的最短路即是他到根的距離。
在新樹中,我們可以記錄兩個點(a,b)找到他們lca前的那兩個點(c,d),如果那兩個點在乙個環中,那麼顯然這兩個點的lca在乙個環中,所以我們需要比較在環上逆時針走的距離以及順時針走的距離,取最小值,再把答案加上dis[a]−dis[c]+dis[b]−dis[d]
即可(畫圖可以知道這個距離就是刨除環上走的那段距離的距離)。
如果那兩個點不在乙個環中,那麼直接像樹一樣,輸出答案即可。
#include#include#include#include#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
inline char nc()
return *p1++;}
inline void read(int &x)
const int n=10005;
const int m=50005;
struct edge;
edge g[m];
int head[n],inum=1;
inline void add(int u,int v,int w,int p)
#define v g[p].v
const int nq=1000005;
int dis[n];
int q[nq],ins[n],l,r;
inline void spfa()
}} int n,m;
const int k=16;
int fat[n][k],depth[n];
int sum[n],ifa[n],vst[n];
int cnt,belong[n],len[n];
void dfs(int u,int fa)
else
}} inline void dfs(int u)
inline void lca(int &u,int &v)
int main()
{ freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
int q,iu,iv,iw,a,b,c,d,len1,len2,lca,ans;
read(n); read(m); read(q);
for (int i=1;i<=m;i++)
read(iu),read(iv),read(iw),add(iu,iv,iw,++inum),add(iv,iu,iw,++inum);
spfa();
dfs(1,0);
cl(head); inum=0;
for (int i=2;i<=n;i++)
add(fat[i][0],i,0,++inum);
for (int k=1;k
BZOJ2125 仙人掌 最短路
題意 求仙人掌上的多元最短路 考慮如果在樹上,u,v兩點之間的最短路為dis u dis v 2 dis lca 因為仙人掌每個點只屬於乙個簡單環,先dfs弄清仙人掌的結構,對於環把環中離根節點最近的點作為父親,環中其他點向這個點連邊,這樣就建出一棵新的樹,如果u,v的lca不在環上,就按照樹的做法...
BZOJ2125 仙人掌 最短路
bzoj2125 建出圓方樹,圓方邊的權值為圓點到環上最高點在dfs樹上的點的距離,這樣就可以記錄下環上兩個點的距離 並在方點處記錄一下環的總長,因為環上兩點間有兩條路徑可走,要分類討論 然後就是樹上求dis的問題,先求lca 然後lca如果是圓點就直接求距離 如果是方點就分類討論一下就好了 cod...
BZOJ2125 最短路 仙人掌最短路
給乙個n個點m條邊的連通無向圖,滿足每條邊最多屬於乙個環,有q組詢問,每次詢問兩點之間的最短路徑。輸入的第一行包含三個整數,分別表示n和m和q 下接m行,每行三個整數v,u,w表示一條無向邊v u,長度為w 最後q行,每行兩個整數v,u表示一組詢問 輸出q行,每行乙個整數表示詢問的答案 9 10 2...