HDU6604 Explota la ciudad (Árbol de extinción)

Volar la ciudad

Límite de tiempo: 5000/5000 MS (Java / otros) Límite de memoria: 131072/131072 K (Java / otros)
Envío total (es): 892 Envío (es) aceptado (s): 477


 

Descripción del problema
El país A y B están en guerra. El país A necesita organizar equipos de transporte para entregar suministros hacia algunas ciudades de centros de mando.

Para garantizar que la entrega funcione de manera eficiente, todas las carreteras del país A funcionan en una sola dirección. Por lo tanto, el mapa del país A puede considerarse como DAG (Gráfico acíclico dirigido). Las ciudades de los centros de mando solo recibieron suministros y no enviaron suministros.

La agencia de inteligencia del país B está informada de manera creíble de que habrá dos ciudades llevando a cabo una tarea crítica de transporte en el país A.

Mientras ** cualquiera ** de las dos ciudades no pueda llegar a una ciudad de centro de mando, la misión fracasa y el país B tendrá una enorme ventaja. Por lo tanto, el país B planea destruir una de las n ciudades del país A y todas las carreteras conectadas directamente. (Si una ciudad que realiza la tarea es también una ciudad centro de mando, es posible destruir la ciudad para que la misión fracase).

Ahora el país B ha formulado q hipótesis sobre las dos ciudades que llevan a cabo la tarea crítica.
Calcule el número de plan que hace que la misión del país A falle.
 

 

Entrada
La primera línea contiene un número entero T (1≤T≤10), que denota el número de casos de prueba.

En cada caso de prueba, la primera línea son dos números enteros n, m, que denotan el número de ciudades y carreteras (1≤n≤100,000,1≤m≤200,000).
Luego siguen m líneas, cada una con dos números enteros u y v, lo que significa que hay una carretera dirigida desde la ciudad u hasta v (1≤u, v≤n, u ≠ v).

La siguiente línea es un número entero q, que denota el número de consultas (1≤q≤100,000)
Y luego siguen q líneas, cada una con dos enteros ayb, lo que significa que las dos ciudades que realizan la tarea crítica son ayb (1 ≤a, b≤n, a ≠ b).

Una ciudad es un centro de mando si y solo si no hay un camino desde ella (su grado de salida es cero).
 

 

Salida
Para cada salida de consulta, una línea con un número entero, significa el número de plan que hace que la misión del país A falle.
 

 

Entrada de muestra
 
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
 

 

Salida de muestra
 
4 3 2 2

 

Idea principal:

Darle un gráfico DAG con 1e5 puntos, todos los puntos con un fuera de grado de 0 son los puntos finales y las consultas 1e5 le darán dos puntos cada vez. Puede borrar cualquier punto del gráfico para hacer al menos uno de estos dos puntos Si el punto no puede llegar al punto final, genere el número de puntos que cumplen las condiciones.

solución:

Antes de que no sepa que esta pregunta es un árbol de extinción, creo que Tarjan reducirá los puntos y encontrará los puntos clave, luego creará un nuevo punto de origen y conectará cada punto final, y finalmente consultará cuántos puntos clave hay en la ruta desde los dos puntos al punto de origen. Más tarde me enteré de que esto no estaba bien para T_T, pero estaba muy cerca, y estaba casi extinto.

A partir de todos los puntos finales, contra la topología, el nodo padre de cada punto es el LCA de todos sus padres (el nodo padre del punto final se juzga específicamente como el punto de origen), y las palabras de LCA se mantienen dinámicamente. La respuesta final son los dos puntos de la consulta y el punto de origen. El camino entre las intersecciones es dis (U, T) + dis (V, T) -dis (lca (U, V), T).

Codigo aceptado

#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记得改宏定义!!!
}

 

Supongo que te gusta

Origin blog.csdn.net/weixin_43851525/article/details/107721761
Recomendado
Clasificación