POJ 3694 Network
边双连通分量+并查集
这题算是水过去的吧,4500ms。应该有更好的写法
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int maxn = 100000 + 10; //结点数量 const int Maxn = 2 * 200000 + 10; //边的数量 int low[maxn]; int dfn[maxn]; int U[Maxn], V[Maxn];//存初始边 int flag[Maxn];//判断第i条边是不是割边 struct Edge { int from, to, id, ans;//ans为1,表示这条边是割边 } edge[Maxn]; vector<int>G[maxn];//邻接表 vector<int>Tree[maxn];//邻接表 int N, M;//N个结点,M条边 int tmpdfn;//时间戳 int tot; int Start, End; int TxT[maxn];//求边双连通分量用的 int FF[maxn]; int Cun[maxn]; int Father[maxn]; int MA, Num, Q, X; void init() { for (int i = 0; i<maxn; i++) G[i].clear(); for (int i = 0; i<maxn; i++) Tree[i].clear(); for (int i = 0; i < maxn; i++) Father[i] = i; memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(flag, 0, sizeof(flag)); memset(TxT, 0, sizeof(TxT)); memset(FF, 0, sizeof(FF)); low[1] = dfn[1] = 1; tmpdfn = 0; tot = 0; Num = 0; } int Find(int x) { if (x != Father[x]) Father[x] = Find(Father[x]); return Father[x]; } void AddEdge(int u, int v) { edge[tot].from = u; edge[tot].to = v; edge[tot].id = tot; edge[tot].ans = 0; G[u].push_back(tot); tot++; edge[tot].from = v; edge[tot].to = u; edge[tot].id = tot; edge[tot].ans = 0; G[v].push_back(tot); tot++; } int Tarjan(int u, int id) { tmpdfn++; int lowu = dfn[u] = tmpdfn; for (int i = 0; i<G[u].size(); i++) { int B = G[u][i]; if (!dfn[edge[B].to]) { int lowv = Tarjan(edge[B].to, edge[B].id); lowu = min(lowu, lowv); if (lowv >= dfn[u]) { if (lowv>dfn[u]) edge[B].ans = 1; } } else if (dfn[edge[B].to]) { if (edge[B].id / 2 == id / 2) continue; lowu = min(lowu, dfn[edge[B].to]); } } low[u] = lowu; return lowu; } void Dfs(int x, int y) { int XZ = 0; for (int i = 0; i<G[x].size(); i++) { int B = G[x][i]; if (!flag[edge[B].id / 2]) { XZ = 1; flag[edge[B].id / 2] = 1; TxT[edge[B].to] = 1; int fu = Find(edge[B].from); int fv = Find(edge[B].to); if (fu != fv) Father[fu] = fv; Dfs(edge[B].to, y + 1); } } if (!XZ&&!y) Father[x] = x; } void Slove() { for (int i = 0; i<2 * M; i++) if (edge[i].ans) { Num++; flag[edge[i].id / 2] = 1; } for (int i = Start; i <= End; i++) { if (!TxT[i]) { TxT[i] = 1; Dfs(i, 0); } } } int FLAGS; void DFS(int now, int len, int END) { FF[now] = 1; if (now == END) { MA = len; FLAGS = 1; return; } for (int i = 0; i < Tree[now].size(); i++) { if (!FF[Tree[now][i]]) { int fu = Find(now); int fv = Find(Tree[now][i]); if (fu == fv) { DFS(Tree[now][i], len, END); if (FLAGS) return; } else if (fu != fv) { Cun[len] = Tree[now][i]; DFS(Tree[now][i], len + 1, END); if (FLAGS) return; } } } } int main() { int CASE = 1; while (~scanf("%d%d", &N, &M)) { if (!N&&!M) break; printf("Case %d:\n", CASE); CASE++; init(); for (int i = 0; i < M; i++) { scanf("%d%d", &U[i], &V[i]); AddEdge(U[i], V[i]); } Start = 1; End = N; Tarjan(1, -1); Slove(); for (int i = 0; i < M; i++) { int fu = Find(U[i]); int fv = Find(V[i]); if (fu == fv) continue; Tree[fu].push_back(fv); Tree[fv].push_back(fu); } scanf("%d", &Q); while (Q--) { MA = 0; FLAGS = 0; memset(FF, 0, sizeof FF); int u, v; scanf("%d%d", &u, &v); int fu = Find(u); int fv = Find(v); if (fu == fv) { printf("%d\n", Num); continue; } DFS(fu ,0, fv); Num = Num - MA; for (int i = 0; i < MA; i++) { int Fa = Find(Cun[i]); Father[Fa] = fu; } printf("%d\n", Num); } printf("\n"); } return 0; }