题目链接
https://ac.nowcoder.com/acm/contest/5667/H
题目大意
有 Q 次操作和一个集合 , 操作有以下类型
①、向集合插入一个数 X
②、从集合中删除一个 X
③、给定一个 X ,问能否从集合中挑选两个数 Y , Z 使得 X , Y , Z 能构成三角形
解题思路
判断三角形的条件为两边之和大于第三边 , 两边之差小于第三边
对于操作③每次询问的 X , 只有两种情况 : 1、X 为最大边 , 2、 X 不为最大边
若 X 为最大边 , 我们只要找到 X 的两个前驱并判断它们的和与 X 的大小关系即可
若 X 不为最大边 , 我们就要找到一个比 X 大的数 , 以及这个数的前驱 , 然后判断它们的差值和 X 的大小关系
对于 X 为最大边的情况我们用 set 简单维护一下就好
对于 X 不为最大边的情况我们考虑用线段树维护每个数和它前驱的差值
然后每次判断一下区间 [ X + 1 , MAX ] 的最小值和 X 的关系即可
因为数很大 , 所以要离散化一下 ( 或者线段树动态开点也行
AC_Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int INF (0x3f3f3f3f3f3f3f3fll);
const int N = 3e5 + 10;
struct Seg_Tree{
int l , r , sum;
}tree[N << 2];
void push_up(int rt)
{
tree[rt].sum = min(tree[rt << 1].sum , tree[rt << 1 | 1].sum);
}
void build(int l , int r , int rt)
{
tree[rt].l = l , tree[rt].r = r , tree[rt].sum = INF;
if(l == r) return ;
int mid = l + r >> 1;
build(l , mid , rt << 1);
build(mid + 1 , r , rt << 1 | 1);
push_up(rt);
}
void update(int pos , int val , int rt)
{
int l = tree[rt].l , r = tree[rt].r;
if(l == r)
{
tree[rt].sum = val ;
return ;
}
int mid = l + r >> 1;
if(pos <= mid) update(pos , val , rt << 1);
else update(pos , val , rt << 1 | 1);
push_up(rt);
}
int query(int L , int R , int rt)
{
int l = tree[rt].l , r = tree[rt].r;
if(L <= l && r <= R) return tree[rt].sum;
int mid = l + r >> 1;
int ans = INF;
if(L <= mid) ans = min(ans , query(L , R , rt << 1));
if(R > mid) ans = min(ans , query(L , R , rt << 1 | 1));
return ans ;
}
set<int>se;
map<int , int>cnt;
int n , m;
int op[N] , a[N] , b[N];
int get_id(int x)
{
return lower_bound(a + 1 , a + 1 + m , x) - a;
}
void solve1(int pos)
{
int x = a[pos];
cnt[x] ++ , se.insert(x);
if(cnt[x] == 1)
{
auto it = se.lower_bound(x);
it -- ;
if(it != se.begin()) update(pos , x - *it , 1);
it ++ , it ++ ;
if(it != se.end())
{
int now = query(get_id(*it) , get_id(*it) , 1);
update(get_id(*it) , min(now , *it - x) , 1);
}
}
else update(pos , 0 , 1);
}
void solve2(int pos)
{
int x = a[pos];
cnt[x] -- ;
if(cnt[x] == 1)
{
auto it = se.lower_bound(x);
it -- ;
if(it != se.begin()) update(pos , x - *it , 1);
else update(pos , INF , 1);
}
else if(!cnt[x])
{
update(pos , INF , 1);
se.erase(x);
auto it = se.lower_bound(x) , jt = it;
if(it != se.end())
{
int y = *it ;
if(cnt[y] == 1)
{
it -- ;
if(it != se.begin()) update(get_id(y) , y - *it , 1);
else update(get_id(y) , INF , 1);
}
}
}
}
bool solve3(int pos)
{
int x = a[pos];
auto it = se.upper_bound(x) , jt = it;
it -- ;
if(it != se.begin())
{
int y = *it;
if(cnt[y] > 1) if(y + y > x) return true;
it -- ;
if(it != se.begin()) if(y + *it > x) return true;
}
it = jt;
int id = get_id(*se.lower_bound(x));
int mi = query(id , m , 1);
if(mi < x) return true;
return false;
}
signed main()
{
ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
se.insert(-INF);
cin >> n;
for(int i = 1 ; i <= n ; i ++)
{
cin >> op[i] >> a[i];
b[i] = a[i];
}
sort(a + 1 , a + 1 + n);
m = unique(a + 1 , a + 1 + n) - a - 1;
build(1 , m , 1);
for(int i = 1 ; i <= n ; i ++) b[i] = get_id(b[i]);
for(int i = 1 ; i <= n ; i ++)
{
if(op[i] == 1) solve1(b[i]);
else if(op[i] == 2) solve2(b[i]);
else
{
if(solve3(b[i])) cout << "Yes\n";
else cout << "No\n";
}
}
return 0;
}