Happy Triangle【思维+权值线段树】

2020牛客多校H题


题意:给Q次对一个multiset的操作:

  1. 放进一个权值x;
  2. 删除存在于multiset内部的一个权值x;
  3. 问一个权值x能否和multiset内的权值构成一个三角形。

  于是,这就是一道分类讨论的题了;我们将要取的multiset中的元素定义为a、b(a \leq b),然后我们考虑x和b的相对位置来进行考虑。

  • x \geq b

  这时候只需要去找x之前两个小于等于x且最接近x的数即可,然后两者之和大于x就是满足条件的了。

  • x \leq b

  这时候,我们可以用一个数据结构来维护大于等于x部分的值,找到一个满足x + a > b \Rightarrow b - a < x这样的条件就可以了,所以就只需要维护每一个数减去它的前驱的最小值即可,这里就可以用离散化之后的权值线段树来维护一下了。

最后附上两组测试样例。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e5 + 7;
int Q, N, lsan[maxN];
struct Question
{
    int op, x;
    Question(int a=0, int b=0):op(a), x(b) {}
    inline void In() { scanf("%d%d", &op, &x); }
} ques[maxN];
multiset<int> st;
multiset<int>::iterator it;
struct tree_node
{
    int lv, rv, minv, siz, preMin;
    tree_node(int a=INF, int b=-INF, int c=INF, int d=0, int f=INF):lv(a), rv(b), minv(c), siz(d), preMin(f) {}
} t[maxN << 2];
void pushup(int rt)
{
    t[rt] = tree_node();
    if(t[lsn].siz)
    {
        t[rt].lv = t[lsn].lv;
        t[rt].rv = t[lsn].rv;
        t[rt].minv = t[lsn].minv;
        t[rt].siz = t[lsn].siz;
    }
    if(t[rsn].siz)
    {
        t[rt].lv = min(t[rt].lv, t[rsn].lv);
        t[rt].rv = max(t[rt].rv, t[rsn].rv);
        t[rt].minv = min(t[rt].minv, t[rsn].minv);
        t[rt].siz += t[rsn].siz;
    }
    if(t[lsn].siz && t[rsn].siz)
    {
        t[rsn].preMin = t[rsn].lv - t[lsn].rv;
        t[rt].minv = min(t[rt].minv, t[rsn].lv - t[lsn].rv);
    }
    else t[rsn].preMin = INF;
}
void update(int rt, int l, int r, int qx, int val)
{
    if(l == r)
    {
        t[rt].siz += val;
        if(t[rt].siz)
        {
            t[rt].lv = t[rt].rv = lsan[l];
            if(t[rt].siz >= 2) t[rt].minv = 0;
            else t[rt].minv = INF;
        }
        else
        {
            t[rt].lv = INF; t[rt].rv = -INF;
            t[rt].minv = INF;
        }
        return;
    }
    int mid = HalF;
    if(qx <= mid) update(Lson, qx, val);
    else update(Rson, qx, val);
    pushup(rt);
}
int query(int rt, int l, int r, int ql, int qr)
{
    if(!t[rt].siz) return INF;
    if(ql <= l && qr >= r) return min(t[rt].minv, t[rt].preMin);
    int mid = HalF;
    if(qr <= mid) return query(QL);
    else if(ql > mid) return query(QR);
    else return min(query(QL), query(QR));
}
int main()
{
    scanf("%d", &Q); N = 0;
    for(int i=1; i<=Q; i++)
    {
        ques[i].In();
        lsan[++N] = ques[i].x;
    }
    sort(lsan + 1, lsan + N + 1);
    N = (int)(unique(lsan + 1, lsan + N + 1) - lsan - 1);
    for(int i=1; i<=Q; i++) ques[i].x = (int)(lower_bound(lsan + 1, lsan + N + 1, ques[i].x) - lsan);
    int a = 0, b = 0, tmp; bool ok, yes_or_no;
    for(int i=1; i<=Q; i++)
    {
        switch (ques[i].op)
        {
            case 1:
            {
                st.insert(ques[i].x);
                update(1, 1, N, ques[i].x, 1);
                break;
            }
            case 2:
            {
                it = st.find(ques[i].x);
                st.erase(it);
                update(1, 1, N, ques[i].x, -1);
                break;
            }
            default:
            {
                it = st.upper_bound(ques[i].x);
                ok = true; yes_or_no = false;
                if(it == st.begin())
                {
                    ok = false;
                }
                else
                {
                    it--;
                    b = *it;
                    if(it == st.begin()) ok = false;
                    else
                    {
                        it--;
                        a = *it;
                    }
                }
                if(ok)
                {
                    if(lsan[a] + lsan[b] > lsan[ques[i].x])
                    {
                        yes_or_no = true;
                    }
                }
                if(!yes_or_no)
                {
                    tmp = query(1, 1, N, ques[i].x, N);
                    if(tmp < lsan[ques[i].x]) yes_or_no = true;
                }
                printf(yes_or_no ? "Yes\n" : "No\n");
                break;
            }
        }
    }
    return 0;
}
/*
3
1 4
1 9
3 6
Yes
*/
/*
4
1 9
1 8
2 8
3 5
No
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值