2020牛客暑期多校训练营(第二场)Happy Triangle
题目链接
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; }
凡所不能将我击倒的,都将使我更加强大