HDU6604 Blow up the city (灭绝树)

Blow up the city

Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 892    Accepted Submission(s): 477


 

Problem Description
Country A and B are at war. Country A needs to organize transport teams to deliver supplies toward some command center cities.

In order to ensure the delivery works efficiently, all the roads in country A work only one direction. Therefore, map of country A can be regarded as DAG( Directed Acyclic Graph ). Command center cities only received supplies and not send out supplies.

Intelligence agency of country B is credibly informed that there will be two cities carrying out a critical transporting task in country A.

As long as **any** one of the two cities can not reach a command center city, the mission fails and country B will hold an enormous advantage. Therefore, country B plans to destroy one of the n cities in country A and all the roads directly connected. (If a city carrying out the task is also a command center city, it is possible to destroy the city to make the mission fail)

Now country B has made q hypotheses about the two cities carrying out the critical task.
Calculate the number of plan that makes the mission of country A fail.
 
Input
The first line contains a integer T (1≤T≤10), denoting the number of test cases.

In each test case, the first line are two integers n,m, denoting the number of cities and roads(1≤n≤100,000,1≤m≤200,000).
Then m lines follow, each with two integers u and v, which means there is a directed road from city u to v (1≤u,v≤n,u≠v).

The next line is a integer q, denoting the number of queries (1≤q≤100,000)
And then q lines follow, each with two integers a and b, which means the two cities carrying out the critical task are a and b (1≤a,b≤n,a≠b).

A city is a command center if and only if there is no road from it (its out degree is zero).
 
Output
For each query output a line with one integer, means the number of plan that makes the mission of country A fail.
 
Sample Input
 
2 8 8 1 2 3 4 3 5 4 6 4 7 5 7 6 8 7 8 2 1 3 6 7 3 2 3 1 3 2 2 1 2 3 1
 
Sample Output
 
4 3 2 2

题目大意:

给你一张1e5个点的DAG图,所有出度为0的点为终点 ,1e5次询问,每次询问给你两个点,你可以删除图中任意一点,使得这两个点中至少一个点无法到达终点,输出满足条件的点数。

解法:

在不知道这题是灭绝树之前,想的是Tarjan缩点后求关键点,再新建一个源点和每个终点相连,最后查询两个点到源点路径上有多少关键点,然而敲完后才发现这样并不对T_T,不过已经很接近,就差灭绝树建树了哈哈。

从所有终点开始逆着拓扑,每个点的父亲结点就是他所有父亲的LCA(终点的父亲结点特判为源点),LCA的话动态维护一下,最后答案就是询问的两点和源点之间的路径交,也就是dis(U, T) + dis(V,T)- dis(lca(U,V),T)。

Accepted code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 1e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }

vector <int> G[N], r[N];
int f[N][25], dep[N];
int dis[N], in[N], n, m;

void Init() {
	MEM(f, 0);
	for (int i = 1; i <= n; i++) {
		G[i].clear(), r[i].clear();
		dep[i] = in[i] = 0;
	}
}
int LCA(int x, int y) {
	if (dep[x] > dep[y])
		swap(x, y);
	for (int i = 20; i >= 0; i--) {
		if (dep[y] - (1 << i) >= dep[x])
			y = f[y][i];
	}
	if (x == y)
		return x;

	for (int i = 20; i >= 0; i--) {
		if (f[x][i] == f[y][i])
			continue;
		x = f[x][i], y = f[y][i];
	}
	return f[x][0];
}
void Topsort() {
	queue <int> q;
	for (int i = 1; i <= n; i++) {
		if (!in[i])
			q.push(i);
	}

	while (!q.empty()) {
		int u = q.front();
		q.pop();

		if (r[u].empty())   // 终点特判
			f[u][0] = 0;
		else {
			int lca = r[u][0];
			for (auto v : r[u])   // 所有父亲的LCA
				lca = LCA(lca, v);
			f[u][0] = lca;
		}

		dep[u] = dep[f[u][0]] + 1;   // 动态维护
		for (int i = 1; (1 << i) <= dep[u]; i++)
			f[u][i] = f[f[u][i - 1]][i - 1];
		for (auto v : G[u]) {
			in[v]--;
			if (!in[v])
				q.push(v);
		}
		G[u].clear();
		G[f[u][0]].push_back(u);   // 存新图
	}
}

int main()
{
	int T; cin >> T;
	while (T--) {
		sc("%d %d", &n, &m);
		Init();

		for (int i = 0; i < m; i++) {
			int u, v;
			sc("%d %d", &u, &v);
			r[u].push_back(v);
			G[v].push_back(u);
			in[u]++;
		}

		Topsort();

		int q;
		sc("%d", &q);
		while (q--) {
			int u, v;
			sc("%d %d", &u, &v);
			int lca = LCA(u, v);
			printf("%d\n", dep[u] + dep[v] - dep[lca]);
		}
	}
	return 0;  // 改数组大小!!!用pair记得改宏定义!!!
}

猜你喜欢

转载自blog.csdn.net/weixin_43851525/article/details/107721761