2020牛客多校第二场H-Happy Triangle (动态开点线段树&SET)

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

Given a multiset MS{MS}MS and q{q}q operations. MS{MS}MS is empty initailly, and operations are in three types, which are as follows:
1. insert an element x{x}x into MS{MS}MS
2. erase an element x{x}x from MS{MS}MS
3. given an integer x{x}x, determine whether you can choose two elements a,b{a, b}a,b in MS{MS}MS that three segments of length a,b,x{a, b, x}a,b,x can make a nondegenerate triangle.

输入描述:

 

The first line contains an integer q (1≤q≤2×105)q~(1\leq q\leq 2\times 10^5)q (1≤q≤2×105), denoting the number of operations.
Following q{q}q lines each contains two integers 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), denoting an operation
1. if op=1{op = 1}op=1, insert an element x{x}x into MS{MS}MS
2. if op=2{op = 2}op=2, erase an element x{x}x from MS{MS}MS, it's guaranteed that there is at least one x{x}x in MS{MS}MS currently
3. if op=3{op = 3}op=3, determine whether you can choose two elements a,b{a, b}a,b in MS{MS}MS that three segments of length a,b,x{a, b, x}a,b,x can make a triangle

输出描述:

For each query, print one line containing a string "Yes" if the answer is yes or "No" if the answer is no.

示例1

输入

复制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

输出

复制No No Yes No

No
No
Yes
No

题目大意:

对于一个集合有加入数X和删除数X两种操作,同时会有一个查询操作,问在集合中是否存在两个数a,b可以与当前查询的X构成一个三角形。

解法:

假设三角形的三条边a,b,c,按照非递减顺序排列,根据三角形性质可知a+b>c。

1、如果X是c,显然a,b尽量大更好;

2、如果X是b,显然a尽量大,c尽量小;

3、如果X是a,选择所有大于a的数当中,相邻两数差值尽量小的两个数更优。

综上,用multiset和map来维护前两种情况,用线段树维护相邻两数的差值(x很大,动态开点就好)。对于一些情况需要特判,例如本身可以构成一个等边三角形,或者X列举的情况没有前驱、后继等等……细节还是挺多的,调了很久。

Accepted code

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

猜你喜欢

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