2020 Niuke DuoSchoolの2番目のH-HappyTriangle(ダイナミックオープニングラインセグメントツリーとSET)

 

制限時間:C / C ++ 2秒、その他の言語4秒
スペース制限:C / C ++ 262144K、その他の言語524288K
64ビットIO形式:%lld

タイトル説明

マルチセットMS {MS} MSおよびq {q} q操作が与えられます。MS {MS} MSは最初は空であり、操作には次の3つのタイプがあり
ます。1。要素x {x} xをMS {MS} MSに挿入します
。2。要素x {x} xをMS {から消去します。 MS} MS3
。整数x {x} xが与えられた場合、長さa、b、x {aの3つのセグメントであるMS {MS} MSで2つの要素a、b {a、b} a、bを選択できるかどうかを判断します。 、b、x} a、b、xは非縮退三角形を作成できます。

説明を入力してください:

 

最初の行には整数q(1≤q≤2×105)q〜(1 \ leq q \ leq 2 \ times 10 ^ 5)q(1≤q≤2×105)が含まれ、演算の数を示します。
次のq {q} q行には、それぞれ2つの整数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)、操作を示し
ます1. op = 1 {op = 1} op = 1の場合、要素x {x} xをMS {MS} MS2に挿入し
ます。op= 2 {op = 2} op = 2の場合、要素x {x} xをMS {MS} MSから消去すると、少なくとも1つあることが保証されます。現在MS {MS} MSのx {x}
x3。op= 3 {op = 3} op = 3の場合、MS {MS}で2つの要素a、b {a、b} a、bを選択できるかどうかを判断します。長さa、b、x {a、b、x} a、b、xの3つのセグメントが三角形を作ることができるMS

出力の説明:

クエリごとに、答えが「はい」の場合は「はい」、答えが「いいえ」の場合は「いいえ」という文字列を含む1行を出力します。

例1

入る

コピー81 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

いいえ
いいえ
はい
いいえ

本旨:

セットの場合、番号Xの追加と番号Xの削除の2つの操作があります。同時に、現在のクエリXと三角形を形成するために、セットに2つの番号aとbがあるかどうかを確認するクエリ操作があります。

解決:

三角形の3つの辺a、b、cが減少しない順序で配置されていると仮定すると、三角形の性質に応じてa + b> cを知ることができます。

1. Xがcの場合、明らかにaとbは可能な限り大きくなります。

2. Xがbの場合、明らかにaは可能な限り大きく、cは可能な限り小さくなります。

3. Xがaの場合、aより大きいすべての数値から選択します。隣接する数値の差が最も小さい2つの数値の方が適しています。

要約すると、マルチセットとマップ使用して最初の2つのケースを維持し、ラインセグメントツリーを使用して2つの隣接する数値の差を維持します(xは大きく、動的オープニングは良好です)。場合によっては、等辺の三角形を形成したり、Xでリストされたケースに先行、後続などがないなど、特別な判断が必要になります。詳細はまだかなり多く、調整に時間がかかります。

受け入れられたコード

#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