HDU - 6604 Blow up the city

题意:

给定一个有 n 个点,m 条边的 DAG,再有 q 次询问,每次询问给定两点 a 和 b,问有多少种情况使得破坏一个点后,a 或 b 不能到达出度为 0 的点。(n, q <= 1e5, m <= 2e5)

链接:

https://vjudge.net/problem/HDU-6604

解题思路:

将边反向,则为求入度为 0 的点不能到达 a 或 b 的情况。引入一个 0 号结点连接入度为 0 的点,则问题等价于破坏一个点后 0 号点不能到达 a 或 b,答案则为 0 号点到 a 的必经点点集并上到 b 的必经点点集的大小。构建支配树后, a n s = d e p [ a ] + d e p [ b ] d e p [ l c a ( a , b ) ] ans=dep[a]+dep[b]-dep[lca(a,b)]

参考代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int maxm = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

vector<int> G[maxn], P[maxn], V[maxn];
int in[maxn], dep[maxn], fa[maxn][21], tp[maxn];
int n, m, tot;

void bfs() {

	queue<int> q;
	for (int i = 1; i <= n; ++i) {

		if (in[i]) continue;
		q.push(i), P[i].pb(0);
	}
	while (!q.empty()) {

		int u = q.front(); q.pop(); tp[++tot] = u;
		for (int i = 0; i < sz(G[u]); ++i) {
			int v = G[u][i];
			if (--in[v] == 0) q.push(v);
			P[v].pb(u);
		}
	}
}

int lca(int u, int v){

	if(dep[u] < dep[v]) swap(u, v);
	for(int i = 20; i >= 0; --i){

		if(dep[fa[u][i]] >= dep[v]) u = fa[u][i];
	}
	if(u == v) return u;
	for(int i = 20; i >= 0; --i){

		if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
	}
	return fa[u][0];
}

void build() {

	bfs();
	for (int i = 1; i <= n; ++i) {

		int u = tp[i], lc = P[u][0];
		for (int j = 1; j < sz(P[u]); ++j) {

			int v = P[u][j];
			lc = lca(lc, v);
		}
		V[lc].pb(u), dep[u] = dep[lc] + 1, fa[u][0] = lc;
		for (int j = 1; j <= 20; ++j) fa[u][j] = fa[fa[u][j - 1]][j - 1];
	}
}

void init() {

	for (int i = 0; i <= n; ++i) in[i] = 0, G[i].clear(), P[i].clear(), V[i].clear();
	tot = 0;
}

int main(){

	int t; scanf("%d", &t);
	while(t--){

		scanf("%d%d", &n, &m);
		init();
		while(m--){

			int u, v; scanf("%d%d", &v, &u);
			G[u].pb(v), P[v].pb(u), ++in[v];
		}
		build();
		int q; scanf("%d", &q);
		while(q--){

			int u, v; scanf("%d%d", &u, &v);
			int lc = lca(u, v);
			int ret = dep[u] + dep[v] - dep[lc];
			printf("%d\n", ret);
		}
	}
	return 0;
}
发布了55 篇原创文章 · 获赞 0 · 访问量 1255

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/102804692