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;
}
posted @ 2020-07-20 15:47  GsjzTle  阅读(193)  评论(0编辑  收藏  举报