时间限制: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记得改宏定义!!!
}