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到根節點距離。那麼如果是一棵仙人掌的話,我們強行套用這個辦法,重新構造一棵樹。對於仙人掌中的乙個環來說,我們把該環中深度最小的點當做這個環的根,然後環上其他點連向該環,非環...