1. 程式人生 > 實用技巧 >2020牛客暑期多校訓練營(第二場)Happy Triangle

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; }