一。tanjian算法(强连通图)
int s[MAXN], stop; int dfn[MAXN], low[MAXN]; int scccnt, sccnum[MAXN]; int dfscnt; inline void tarjan(int now){ dfn[now] = low[now] = ++dfscnt; s[stop++] = now; for (int i = he[now]; i != 0 ; i = ne[i]){ if (!dfn[ed[i]]) { tarjan(ed[i]); low[now] = min(low[now], low[ed[i]]); } else if(!sccnum[ed[i]]) { low[now] = min(low[now], dfn[ed[i]]); } } if (dfn[now] == low[now]) { scccnt++; do { sccnum[s[--stop]] = scccnt; } while(s[stop] != now); } }
练习:(割点割边+缩点+dfs)模板:P3387
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 struct sb 5 { 6 int to,nx; 7 }g[200001]; 8 int x[100001],y[100001],t[100001]; 9 int cnt,list[200001]; 10 void add(int x,int y) 11 { 12 g[++cnt].to=y; g[cnt].nx=list[x]; list[x]=cnt; 13 } 14 int dfn[100001],low[100001],num,stack[100010],top,color[100010],col,sum[100010],vis[100010]; 15 void tarjan(int x) 16 { 17 dfn[x]=++num; 18 low[x]=num; 19 vis[x]=1; 20 stack[++top]=x; 21 for (int i=list[x];i;i=g[i].nx) 22 { 23 int y=g[i].to; 24 if (!dfn[y]) 25 { 26 tarjan(y); 27 low[x]=min(low[x],low[y]); 28 } 29 else if (vis[y]) low[x]=min(low[x],dfn[y]); 30 } 31 if (dfn[x]==low[x]) 32 { 33 ++col; 34 while (stack[top+1]!=x) 35 { 36 color[stack[top]]=col; 37 sum[col]+=t[stack[top]]; 38 vis[stack[top--]]=false; 39 } 40 } 41 } 42 int f[100010]; 43 void dfs(int x) 44 { 45 if (f[x]) return; 46 f[x]=sum[x]; 47 int maxsum=0; 48 for (int i=list[x];i;i=g[i].nx) 49 { 50 int y=g[i].to; 51 if (!f[y]) dfs(y); 52 maxsum=max(maxsum,f[y]); 53 } 54 f[x]+=maxsum; 55 } 56 int main () 57 { 58 int n,m; 59 cin>>n>>m; 60 for (int i=1;i<=n;i++) cin>>t[i]; 61 for (int i=1;i<=m;i++) 62 { 63 cin>>x[i]>>y[i]; 64 add(x[i],y[i]); 65 } 66 for (int i=1;i<=n;i++) 67 if (!dfn[i]) tarjan(i); 68 memset(g,0,sizeof(g)); 69 memset(list,0,sizeof(list)); 70 cnt=0; 71 for (int i=1;i<=m;i++) 72 if (color[x[i]]!=color[y[i]]) 73 add(color[x[i]],color[y[i]]); 74 int ans=0; 75 for (int i=1;i<=col;i++) 76 if (!f[i]) 77 { 78 dfs(i); 79 ans=max(ans,f[i]); 80 } 81 cout<<ans; 82 83 }
二。树的直径 树的重心(分治)
int sz[MAXN]; inline int dfs_sz(int now, int f){ sz[now] = 1; for(int i = he[now]; i; i = ne[i]){ Edge& e = ed[i]; if(!vis[e.to] && e.to != f){ sz[now] += dfs_sz(e.to, now); } } return sz[now]; } inline int dfs_find(int now, int f, int tot){ for(int i = he[now]; i; i = ne[i]){ Edge& e = ed[i]; if(!vis[e.to] && e.to != f){ if(sz[e.to]*2 > tot) return dfs_find(e.to, now, tot); } } return now; } inline int findg(int s){ dfs_sz(s, -1); return dfs_find(s, -1, sz[s]); }
练习:POJ1655
三。最近公共祖先
(倍增LCA)枚举答案的二进制位
int fa[maxn][20], dep[maxn], d[maxn]; void build_lca(int now){ for(int i = 1 ; i < 20 && fa[now][i] ; i++){ fa[now][i] = fa[fa[now][i-1]][i-1]; } for(int i = he[now]; i ; i = ne[i]){ Edge &e = ed[i]; if(e.to == fa[now][0]) continue; fa[e.to][0] = now; dep[e.to] = dep[now] + 1; d[e.to] = d[now] + e.dist; build_lca(e.to); } } int get_lca(int x,int y) { if(dep[x] != dep[y]){ if(dep[y] > dep[x]) swap(X,y); for(int i = 19 ; i >= 0 ; i--){ if(dep[fa[x][i]] >= dep[y]) x = fa[x][i]; } } if(x == y) return x; for(int i = 19 ; i >= 0 ; i--){ if(fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } } return fa[x][0]; }
例题:P1073 P2746 P2860