原來的題解:
這題有一步是要求1-n中間所有最短路邊上的關鍵路徑,也就是最短路邊組成的子圖的橋
當時訓練賽我還不會求橋,就去網上找有向圖求橋的**
然後wa了半天。。。後來發現別人都是先轉換成無向圖再求橋的
這裡更新為了lyd《演算法競賽高階指南》上求橋的板子
如果搜尋樹上某個點u的子節點v,dfn[u]理性分析一下,這樣說明v無法通過一條路徑到達u本身和之前訪問到的點,那麼u,v這條邊一旦斷開,那麼v和u就將不連通
注意重邊的情況,我們再前向星陣列中存雙向邊是(2,3)(4,5)一對一對的,那麼在更新low的時候,要判斷上一條到達u點的邊是否跟當前列舉的邊在本質上是一條邊,如果是,那麼就不能用來更新low。
#include#define maxl 100010
using namespace std;
int n,m,cnt1,cnt2,cnt3,ind;
int ehead1[maxl],ehead2[maxl],ehead3[maxl];
int dfn[maxl],low[maxl];
long long dis1[maxl],dis2[maxl];
struct edge
edg[maxl];
struct ed
e1[maxl<<1],e2[maxl<<1],e3[maxl<<1];
typedef pair p;
priority_queue,greater> q;
bool in[maxl],edin[maxl],cut[maxl];
typedef pair pp;
typedef pair ppp;
map mp;
inline void add1(int u,int v,int l,int id)
inline void add2(int u,int v,int l,int id)
inline void add3(int u,int v,int l,int id)
inline void prework()}
inline void tarjan(int u,int in_edge)
else if(i!=(in_edge^1))
low[u]=min(low[u],dfn[v]); }}
inline void mainwork()
while((d.first>dis1[u] || in[u]) && !q.empty());
in[u]=true;
for(int i=ehead1[u];i;i=e1[i].nxt) }
}while(!q.empty())
q.pop();
memset(in,false,sizeof(bool)*(n+1));
dis2[2]=0;q.push(make_pair(0ll,2));
while(!q.empty())
while((d.first>dis2[u] || in[u]) && !q.empty());
in[u]=true;
for(int i=ehead2[u];i;i=e2[i].nxt) }
}cnt3=1;
for(int i=1;i<=m;i++)
}ind=0;
memset(dfn,0,sizeof(int)*(n+1));
memset(low,0,sizeof(int)*(n+1));
tarjan(1,0);}
inline void print()
else
}} int main()
tarjan縮點 求橋模板
這麼一看縮點用tarjan也沒必要啊,用之前那個存反向邊dfs兩次的做法就行了 縮點過程就是遍歷邊,兩側不同scc就加邊 include pragma comment linker,stack 1024000000,1024000000 include include include include...
tarjan雙聯通求割點和橋模板
詳見 求割點 int n,m,stamp,low 1005 dfn 1005 iscut 1005 iscut記錄的為割點 vector vec 1005 void tarjan int index,int fa else if dfn tmp fa if fa 0 child 1 iscut in...
割邊(橋 模板
用tarjan求橋並輸出 include include include include using namespace std const int maxn 10010 int n,m,x,y,index dfn maxn low maxn ans,a index 代表當前的時間戳 vectorg...