Campo de treinamento multi-escolar de verão de 2020 Niuke (oitavo jogo) A.Jogo All-Star (Árvore de segmentos de linha de conquista e divisão do tempo)

Limite de tempo: C / C ++ 5 segundos, outros idiomas 10 segundos
Limite de espaço: C / C ++ 262144K, outros idiomas 524288K
64bit IO Formato:% lld

Descrição do título

No país de Apolo, o basquete é o esporte mais popular. Existem n jogadores de basquete e m fãs de basquete. Os jogadores de basquete são numerados de 1 a n. Os fãs de basquete são numerados de 1 a m.
Um fã de basquete pode ser um fã de vários jogadores.
O torcedor de basquete i gosta de assistir ao jogo do jogador j se uma das seguintes condições for atendida:

  • Fã de basquete i é fã do jogador de basquete j.
  • Há um fan i 'e um jogador j', ambos fan i e fan i 'gostam de assistir ao jogo do jogador j', e fan i 'é como assistir ao jogo do jogador j.

O All-Star Game é um jogo de basquete de exibição anual. Você precisa selecionar alguns jogadores para o Jogo All-Star. Um torcedor assistirá ao All-Star Game se quiser assistir ao jogo de um jogador selecionado (ou seja, pelo menos um dos jogadores que o torcedor gosta de assistir foi selecionado). Você precisa decidir o número mínimo de jogadores que deve ser selecionado para o All-Star Game para que todos os fãs de basquete assistam ao jogo.
Inicialmente, alguns jogadores de basquete terão alguns fãs. Existem q mudanças no relacionamento entre jogadores e fãs de basquete.
Após cada mudança de q, imprima um inteiro --- o número mínimo de jogadores que você deve selecionar para fazer com que todos os fãs de basquete assistam ao jogo. Imprima "-1" se for impossível.

Digite a descrição:

The first line contains three integers n, m and q (1≤n,m,q≤2×1051 \le n, m, q \le 2 \times 10^51≤n,m,q≤2×105) - the number of basketball players, the number of basketball fans and the number of changes respectively.

Then n lines follow. The i-th line starts with one integer kik_iki​ (0≤ki≤m0 \le k_i \le m0≤ki​≤m) - the initial number of fans of basketball player i, then contains kik_iki​ different integers - present the fans of player i.

∑i=1nki≤5×105\sum_{i=1}^n k_i \le 5 \times 10^5∑i=1n​ki​≤5×105.

Then q lines follow. The i-th line contains two integers x and y (1≤x≤m1 \le x \le m1≤x≤m, 1≤y≤n1 \le y \le n1≤y≤n). If fan x is a fan of basketball player y, then fan x will be not a fan of player y, otherwise, fan x will be a fan of player y.

Descrição de saída:

After each change print one integer --- the minimum number of players need to be selected into All-Star Game so that all basketball fans will watch the game. Pritn "-1" if it is impossible.

Exemplo 1

entrar

cópia de

4 4 6

2 1 2

0

2 2 3

1 4

4 2

2 3

2 1

2 2

4 2

4 1

4 4 6
2 1 2
0
2 2 3
1 4
4 2
2 3
2 1
2 2
4 2
4 1

Resultado

2 3 -1 3 4 3

2
3
-1
3
4
3

Se o significado da pergunta não for fácil de explicar, assuma que você já sabe ^ _ ^

solução:

Em primeiro lugar, este é um problema de manutenção dinâmica de blocos conectados , e o problema não é forçado a estar online, então você pode usar a árvore de linha de divisão e conquista de tempo (doravante referida como SJFZ) para resolvê-lo.

SJFZ simplesmente entende que leva o número da consulta como um subscrito e, em seguida, marca o período de tempo em que a borda uv aparece , mescla quando aparece e cancela a subárvore após a recursão ser concluída.

Uma análise mostra que o resultado de cada vez é o número de blocos conectados contendo ventiladores.Se um bloco conectado possuir apenas ventiladores, então a saída é -1, pois nenhum jogador pode fazê-lo ir para o jogo. Portanto, precisamos apenas manter o número de blocos conectados contendo ventiladores enquanto gravamos SJFZ e se há ventiladores sozinhos em um bloco conectado para determinar se a resposta é -1.

Número de blocos conectados de ventiladores : Inicialmente, cada ventilador pode ser marcado. Hav [x] = true significa que o bloco conectado contém ventiladores. Se x for mesclado em y, então hav [y] | = hav [x], ao revogar Basta atualizar e voltar.

Existem ventiladores conectados individualmente em blocos conectados : Basta marcá-los quando os ventiladores conectarem a primeira borda e excluir a última borda.

Se você já aprendeu o SJFZ, basta olhar para as funções mesclar e desfazer As outras são modelos.

Código aceito

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

#define sc scanf
#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 = 2e5 + 100;
const int M = 7e5 + 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; }

struct node
{
	int u, v, id;
};
struct Node
{
	int x, y, l, r;
}st[M];
vector <pir> ver[M * 4];
vector <node> ask[N];
int fz[N * 2], sz[N * 2], n, m, q;
map <pir, int> vis;
map <int, int> fan;
int ans[N], fans, cut, top;
bool ok[N * 2];   // 是否有fans

void Init() {
	for (int i = 1; i <= n + m; i++) {
		fz[i] = i, sz[i] = 1;
		if (i > n)
			ok[i] = true;
	}
	cut = fans = m;  // 连通块,单独粉丝
}
int Find(int x) {
	while (x != fz[x])
		x = fz[x];
	return x;
}
void Merge(int x, int y) {
	x = Find(x), y = Find(y);
	if (x == y) {
		st[++top] = { 0, 0 };
		return;
	}
	if (sz[x] > sz[y])
		swap(x, y);
	fz[x] = y, sz[y] += sz[x];
	st[++top] = { x, y, ok[x], ok[y] }; // 保留当前状态
	if (ok[x] && ok[y]) // fans合并
		cut--;
	ok[y] |= ok[x];

	if (x > n && sz[x] == 1) // 单独的fans少了
		fans--;
}
void Cancle() {
	int x = st[top].x, y = st[top].y;
	int ok1 = st[top].l, ok2 = st[top].r;
	top--;
	if (!x || !y)
		return;
	fz[x] = x, sz[y] -= sz[x];
	ok[x] = ok1, ok[y] = ok2;
	if (ok1 && ok2)  // 都有fans断开
		cut++;
	if (x > n && sz[x] == 1)
		fans++;
}
#define ls (o << 1)
#define rs (ls | 1)
void Update(int o, int L, int R, int l, int r, pir val) {
	if (L >= l && R <= r)
		ver[o].push_back(val);
	else {
		int mid = (L + R) >> 1;
		if (mid >= l)
			Update(ls, L, mid, l, r, val);
		if (mid < r)
			Update(rs, mid + 1, R, l, r, val);
	}
}
void Ask(int o, int L, int R) {
	for (auto it : ver[o])
		Merge(it.first, it.second);
	if (L == R) {
		for (auto it : ask[L]) {
			int u = it.u, v = it.v;
			ans[it.id] = fans ? -1 : cut;
		}
	}
	else {
		int mid = (L + R) >> 1;
		Ask(ls, L, mid), Ask(rs, mid + 1, R);
	}
	int sz = SZ(ver[o]);
	while (sz--)
		Cancle();
}

int main()
{
#ifdef OlaMins
	freopen("D:/input.txt", "r", stdin);
	//freopen("D:/output.txt", "w", stdout);
#endif
	
	cin >> n >> m >> q;
	Init();
	for (int i = 1; i <= n; i++) {
		int k, u;
		sc("%d", &k);
		while (k--) {
			sc("%d", &u);  // fans
			u += n;
			vis[{u, i}] = 1;
		}
	}
	for (int i = 2; i <= q + 1; i++) {
		int x, y;
		sc("%d %d", &x, &y); // fans, player
		x += n; 

		if (vis.count({ x, y })) {  // 有边,此时要删除
			int lst = vis[{x, y}];
			vis.erase({ x, y });
			Update(1, 1, q + 1, lst, i - 1, { x, y });
		}
		else  // 无边,标记时间
			vis[{x, y}] = i;
		ask[i].push_back({ x, y, i });
	}
	for (auto it : vis)
		Update(1, 1, q + 1, it.second, q + 1, { it.first.first, it.first.second });
	Ask(1, 1, q + 1);
	for (int i = 2; i <= q + 1; i++)
		printf("%d\n", ans[i]);
	return 0; // 改数组大小!!!用pair改宏定义!!!
}

 

Acho que você gosta

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