【模板】割點(割頂)
阿新 • • 發佈:2019-01-24
題目
思路
複習tarjan
我們維護兩個陣列dfn[]和low[],dfn[u]表示頂點u第幾個被(首次)訪問,low[u]表示頂點u及其子樹中的點,通過非父子邊(回邊),能夠回溯到的最早的點(dfn最小)的dfn值(但不能通過連線u與其父節點的邊)。對於邊(u, v),如果low[v]>=dfn[u],此時u就是割點。
程式碼
#include<iostream> #include<cstdio> using namespace std; const int maxn = 10007; const int maxm = 100007; struct node { int x,y; }E[maxm],ne[maxm]; int n,m,tm = 0,top = 0,tot = 0; int W[maxn],dfn[maxn],low[maxn],Head[maxn],Next[maxm],S[maxn],V[maxn],sd[maxn]; int nh[maxn],nn[maxm],in[maxn],D[maxn]; void tarjan(int x) { dfn[x] = low[x] = ++tm; S[++top] = x; V[x] = 1; for (int y,i = Head[x]; i; i = Next[i]) { y = E[i].y; if (!dfn[y]) { tarjan(y); low[x] = min(low[x],low[y]); } else if (V[y]) { low[x] = min(low[x],low[y]); } } if (dfn[x] == low[x]) { int y; while (y = S[top--]) { V[y] = 0; sd[y] = x; if (y==x) break; W[x] +=W[y]; } } return; } int main() { scanf("%d%d",&n,&m); for (int i = 1; i<=n; i++) { scanf("%d",&W[i]); } for (int i = 1; i<=m; i++) { scanf("%d%d",&E[i].x,&E[i].y); Next[i] = Head[E[i].x]; Head[E[i].x] = i; } for (int i = 1; i<=n; i++) { if (!dfn[i]) { tarjan(i); } } for (int x,y,i = 1; i<=m; i++) { x = sd[E[i].x]; y = sd[E[i].y]; if (x!=y) { ne[++tot].x = x; ne[tot].y = y; nn[tot] = nh[x]; nh[x] = tot; in[y]++; } } top = 0; for (int i = 1; i<=n; i++) { if (sd[i] == i && !in[i]) { S[++top] = i; D[i] = W[i]; } } while (top) { int x = S[top--]; for (int y,i = nh[x]; i; i = nn[i]) { y = ne[i].y; D[y] = max(D[y],D[x]+W[y]); if (--in[y] == 0) { S[++top] = y; } } } int ans = 0; for (int i = 1; i<=n; i++) { ans = max(ans,D[i]); } cout<<ans<<endl; return 0; }