2020 segundo H-Happy Triangle de Niuke Duo School (árbol de segmento de línea de apertura dinámica y SET)

 

Límite de tiempo: C / C ++ 2 segundos, otros idiomas 4 segundos
Límite de espacio: C / C ++ 262144K, otros idiomas 524288K
64bit IO Formato:% lld

Descripción del Título

Dada una MS {MS} MS de múltiples conjuntos y q {q} q operaciones. MS {MS} MS está vacío inicialmente, y las operaciones son de tres tipos, que son los siguientes:
1. insertar un elemento x {x} x en MS {MS} MS
2. borrar un elemento x {x} x de MS { MS} MS
3. dado un número entero x {x} x, determine si puede elegir dos elementos a, b {a, b} a, b en MS {MS} MS que tres segmentos de longitud a, b, x {a , b, x} a, b, x pueden formar un triángulo no degenerado.

Ingrese descripción:

 

La primera línea contiene un número entero q (1≤q≤2 × 105) q ~ (1 \ leq q \ leq 2 \ times 10 ^ 5) q (1≤q≤2 × 105), que denota el número de operaciones.
Después de q {q} q líneas, cada una contiene dos enteros op, x (op∈ {1,2,3}, 1≤x≤109) op, x ~ (op \ in \ {1,2,3 \}, 1 \ leq x \ leq 10 ^ 9) op, x (op∈ {1,2,3}, 1≤x≤109), que denota una operación
1. si op = 1 {op = 1} op = 1, inserte una elemento x {x} x en MS {MS} MS
2. si op = 2 {op = 2} op = 2, borre un elemento x {x} x de MS {MS} MS, se garantiza que hay al menos uno x {x} x en MS {MS} MS actualmente
3. si op = 3 {op = 3} op = 3, determine si puede elegir dos elementos a, b {a, b} a, b en MS {MS} MS que tres segmentos de longitud a, b, x {a, b, x} a, b, x pueden formar un triángulo

Descripción de salida:

Para cada consulta, imprima una línea que contenga una cadena "Sí" si la respuesta es sí o "No" si la respuesta es no.

Ejemplo 1

entrar

Copiar 8 1 1 3 1 1 1 3 2 3 1 1 2 2 1 3 1

8
1 1
3 1
1 1
3 2
3 1
1 2
2 1
3 1

Salida

Recuperación No No Si No

No
No
si
No

Idea principal:

Para un conjunto, hay dos operaciones de sumar el número X y eliminar el número X. Al mismo tiempo, habrá una operación de consulta para preguntar si hay dos números ayb en el conjunto para formar un triángulo con la consulta actual X.

solución:

Suponiendo que los tres lados a, byc del triángulo están dispuestos en un orden no decreciente, a + b> c se puede conocer de acuerdo con la naturaleza del triángulo.

1. Si X es c, obviamente ayb son tan grandes como sea posible;

2. Si X es b, obviamente a es lo más grande posible y c es lo más pequeño posible;

3. Si X es a, elija entre todos los números mayores que a, los dos números con la menor diferencia entre números adyacentes son mejores.

En resumen, use multiset y map para mantener los dos primeros casos, y use un árbol de segmento de línea para mantener la diferencia entre dos números adyacentes (x es grande y la apertura dinámica es buena). Para algunos casos, se requiere un juicio especial, por ejemplo, puede formar un triángulo equilátero, o los casos enumerados por X no tienen predecesor, sucesor, etc ... Los detalles aún son muchos, y se ha ajustado durante mucho tiempo.

Codigo aceptado

#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 = 1e6 + 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; }

int mi[N * 60], ls[N * 60], rs[N * 60];
unordered_map <int, int> rt, mp;
multiset <int> st;
int idx, n = 1e9;

void Pushdown(int o) {
	if (!ls[o])
		ls[o] = ++idx, mi[idx] = INF;
	if (!rs[o])
		rs[o] = ++idx, mi[idx] = INF;
}
void Update(int o, int L, int R, int x, int val) {
	if (L == R && L == x) {
		mi[o] = val;
		return;
	}
	Pushdown(o);
	int mid = (L + R) >> 1;
	if (mid >= x)
		Update(ls[o], L, mid, x, val);
	else
		Update(rs[o], mid + 1, R, x, val);
	mi[o] = min(mi[ls[o]], mi[rs[o]]);
}
int Ask(int o, int L, int R, int l, int r) {
	if (L >= l && R <= r)
		return mi[o];
	Pushdown(o);
	int mid = (L + R) >> 1, ans = INF;
	if (mid >= l)
		Min(ans, Ask(ls[o], L, mid, l, r));
	if (mid < r)
		Min(ans, Ask(rs[o], mid + 1, R, l, r));
	return ans;
}
bool Bigest(int x) {
	if (mp[x]) {  // 有x
		auto pre = st.lower_bound(x);
		if (pre == st.begin())
			return false;
		return true;
	}
	else {  // 无x
		auto pre = st.lower_bound(x);
		if (pre == st.begin())  // 无前驱
			return false;
		pre--;
		if (pre == st.begin()) // 无前驱1
			return false;
		auto pre1 = pre;
		pre1--;
		if (*pre1 + *pre > x)
			return true;
		return false;
	}
}
bool Pre(int x) {
	auto pre = st.lower_bound(x);
	if (pre == st.begin()) // 无前驱
		return false;
	return true;
}
bool Nxt(int x, int &ans) {
	auto nxt = st.upper_bound(x);
	if (nxt == st.end())   // 无后继
		return false;
	ans = *nxt;
	return true;
}
bool Mid(int x) {
	if (mp[x]) {  // 有x
		int nxt;
		if (Pre(x))
			return true;
		if (Nxt(x, nxt)) {
			if (x + x > nxt)
				return true;
		}
		return false;
	}
	else { // 无x
		auto nxt = st.upper_bound(x);  // 后继
		if (nxt == st.end())
			return false;
		auto pre = nxt;
		if (pre == st.begin())  // 前驱
			return false;
		pre--;
		if (*pre + x > *nxt)
			return true;
		return false;
	}
}
bool Smallest(int x) {
	if (mp[x]) {
		auto nxt = st.upper_bound(x);
		if (nxt == st.end())
			return false;
		if (2 * x > *nxt)
			return true;
	}
	int c = Ask(rt[1], 1, n, x + 1, n);
	if (c < x)
		return true;
	return false;
}

int main()
{
	rt[1] = ++idx, mi[1] = INF;   // 动态开点
	int q;
	cin >> q;
	while (q--) {
		int op, x, y;
		sc("%d %d", &op, &x);
		if (op == 1) {              // 加入点X
			mp[x]++, st.insert(x);
			if (mp[x] == 1) {       // 是集合中唯一的X
				auto it = st.lower_bound(x);
				if (it == st.begin())    // 无前驱
					Update(rt[1], 1, n, x, INF);
				else {  // 有前驱,更新x差值
					it--;
					Update(rt[1], 1, n, x, x - *it);
				}

				it = st.upper_bound(x); // 后继
				if (it != st.end()) {
					if (mp[*it] == 1)
						Update(rt[1], 1, n, *it, *it - x);
				}
			}
			else // 差值为0
				Update(rt[1], 1, n, x, 0);
		}
		else if (op == 2) {    // 删除x
			auto it = st.lower_bound(x); 
			st.erase(it), mp[x]--;

			if (mp[x] == 1) {  // 找前驱
				auto it = st.lower_bound(x);
				if (it == st.begin()) // 无前驱
					Update(rt[1], 1, n, x, INF);
				else {
					it--;
					Update(rt[1], 1, n, x, x - *it);
				}
			}
			else if (!mp[x]) {
				Update(rt[1], 1, n, x, INF);
				if (st.empty())
					continue;
				auto it = st.upper_bound(x);
				if (it == st.end())  // 无后继
					continue;
				if (it == st.begin()) { // 后继且无前驱
					if (mp[*it] == 1)
						Update(rt[1], 1, n, *it, INF);
				}
				else if (mp[*it] == 1) {
					auto pre = it; pre--;
					Update(rt[1], 1, n, *it, *it - *pre);
				}
			}
		}
		else {
			if (SZ(st) <= 1) {
				puts("No");
				continue;
			}
			if (mp[x] >= 2) {
				puts("Yes");
				continue;
			}
			if (Bigest(x))   // X当作C
				puts("Yes");
			else if (Mid(x))   // X当作b
				puts("Yes");
			else if (Smallest(x))  // X当作a
				puts("Yes");
			else
				puts("No");
		}
	}
	return 0;  // 改数组大小!!!用pair记得改宏定义!!!
}

 

Supongo que te gusta

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