仙人掌最短路 BZOJ 2125 最短路

2021-07-14 07:25:50 字數 1646 閱讀 9241

題解:

首先如果這是一棵樹的話,那麼我們只需要選定乙個根,之後掃一遍這棵樹,詢問的話即是兩點到根節點的距離之和減去二倍的兩點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...