BZOJ2125 最短路(仙人掌,圓方樹)

2022-03-20 05:30:27 字數 1636 閱讀 7743

bzoj

求仙人掌上兩點間的最短路

終於要構建圓方樹啦

首先構建出圓方樹,因為是仙人掌,和一般圖可以稍微的不一樣

直接\(tarjan\)縮點,對於每乙個強連通分量構建方點(只有乙個點的就不要建了)

圓方邊的權值定義為到\(dfs\)(\(tarjan\)不就是搞了一棵\(dfs\)樹出來嗎?)樹上深度最小的點的最短距離。

為什麼會有最短距離?因為它是乙個環啊,走兩側的距離是不同的。

將圓方樹樹鏈剖分,和普通的求距離一樣,先求解\(lca\)

如果\(lca\)是圓點,那麼和普通的樹沒有任何區別,直接求解

如果是方點,那麼意味這這兩個點的祖先在乙個環上

因此,最短路要考慮這個環上這兩個祖先的較小距離

對於方點維護一下環的長度,記錄一下每個點到達深度最小的點是否經過返祖邊

求距離時,首先跳到這兩個環上的點,然後計算一下距離就好啦。

怎麼跳到環上?

方案一:不用樹鏈剖分了,我直接用倍增

方案二:考慮樹鏈剖分每個點只有乙個重兒子,現在要求的是當前這個點到達\(lca\)的所有祖先中,是\(lca\)兒子的那個點。

我們分類討論一下,如果它是重兒子,那就是\(lca\)的\(dfs\)序的後面那個點。

如果不是重兒子,那麼它就是一條重鏈的起點,並且他的父親是\(lca\)。

既然這樣,沿著重鏈跳就好啦

#include#include#include#include#include#include#include#include#include#includeusing namespace std;

#define ll long long

#define rg register

#define max 20000

inline int read()

struct line;

struct link

;h[u]=cnt;

e[++cnt]=(line);h[v]=cnt;

}}t,g;

int n;

struct rst

} void dfs2(int u,int tp)

int lca(int u,int v)

int jump(int u,int lca)

int query(int u,int v)

}rst;

int dfn[max],low[max],tim,tp[max],dep[max];

int fa[max];

ll dis[max];

int s[max],tot,m,q;

void build(int u,int y,int d)

}void tarjan(int u,int ff)

else low[u]=min(low[u],dfn[v]);

if(dfn[u]} for(int i=g.h[u];i;i=g.e[i].next) }

int main()

tarjan(1,0);

rst.dfs1(1,0);rst.dfs2(1,1);

while(q--)printf("%d\n",rst.query(read(),read()));

return 0;

}

BZOJ2125 仙人掌 最短路

題意 求仙人掌上的多元最短路 考慮如果在樹上,u,v兩點之間的最短路為dis u dis v 2 dis lca 因為仙人掌每個點只屬於乙個簡單環,先dfs弄清仙人掌的結構,對於環把環中離根節點最近的點作為父親,環中其他點向這個點連邊,這樣就建出一棵新的樹,如果u,v的lca不在環上,就按照樹的做法...

BZOJ2125 仙人掌 最短路

bzoj2125 建出圓方樹,圓方邊的權值為圓點到環上最高點在dfs樹上的點的距離,這樣就可以記錄下環上兩個點的距離 並在方點處記錄一下環的總長,因為環上兩點間有兩條路徑可走,要分類討論 然後就是樹上求dis的問題,先求lca 然後lca如果是圓點就直接求距離 如果是方點就分類討論一下就好了 cod...

仙人掌最短路 BZOJ 2125 最短路

題解 首先如果這是一棵樹的話,那麼我們只需要選定乙個根,之後掃一遍這棵樹,詢問的話即是兩點到根節點的距離之和減去二倍的兩點lca到根節點距離。那麼如果是一棵仙人掌的話,我們強行套用這個辦法,重新構造一棵樹。對於仙人掌中的乙個環來說,我們把該環中深度最小的點當做這個環的根,然後環上其他點連向該環,非環...