Sol - P7687
本题考查知识点是割点和桥以及对 tarjan 算法的理解。
根据题意或者根据样例,我们不难得出两个结论:
-
是关键通信线路的一定是桥,桥不一定是关键通信线路;
-
满足条件的桥一定会使有一个连通块不存在含服务 \(A\) 的点或服务 \(B\) 的点。
因此,在 tarjan 的过程中,为关键通信线路的边需要满足下列两个条件:
-
该边为桥;
-
在 DFS 子树里,服务 \(A\) 数量为 \(0\) 或 \(K\),或服务 \(B\) 数量为 \(0\) 或 \(L\)。
于是这道题就解决了。
tarjan 代码如下。
void tarjan(int u,int fa){
dfn[u]=low[u]=++Cnt;
for(int v:e[u]){
if(v==fa)continue;
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u] && (!a[v] || !b[v] || a[v]==k || b[v]==l)){
//这条边是桥,且子树中要么占据所有 A 或 B 服务,要么一个 A 或 B 服务都没有
ans.push_back(make_pair(u,v));
}
a[u]+=a[v]; b[u]+=b[v];
}else low[u]=min(low[u],dfn[v]);
}
}