题目思路:首先需要理解一个规律:

根据三角形定义,若牛客练习赛90 D.妄想集合 线段树+Set+数学_数据结构构成三角形,则牛客练习赛90 D.妄想集合 线段树+Set+数学_数据结构_02c且牛客练习赛90 D.妄想集合 线段树+Set+数学_数据结构_03不为牛客练习赛90 D.妄想集合 线段树+Set+数学_算法_04,很容易发现:当数列中的所有数都是斐波那契数列中的数的时候,任意三个数不能组成三角形

那么我们对斐波那契数列进行研究,可以发现到第牛客练习赛90 D.妄想集合 线段树+Set+数学_数据_05项之后数值已经非常大,超过了题目可能出现的数据范围。因此对于不可重集合中元素数量大于牛客练习赛90 D.妄想集合 线段树+Set+数学_数据_05的情况,对于本体的数据范围一定存在三角形。

那么我们用一棵线段树维护区间集和元素总个数,用一个类似邻接表的结构储存每个叶节点中的集合。每次首先查询区间内的元素总数目。如果数目大于牛客练习赛90 D.妄想集合 线段树+Set+数学_数据_05,那么区间一定有解。对于小于等于牛客练习赛90 D.妄想集合 线段树+Set+数学_数据_05的情况,直接区间暴力二分查找,检索满足题意的情况。

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 1e6;
int d[N][70], cnt[N];

set<int> S;

int n, m, tree[N << 2], lazy[N << 2];

inline int read() {
int f = 1, x = 0; char s = getchar();
while(s < '0'||s > '9'){ if(s =='-') f = -1; s = getchar(); }
while(s >= '0' && s <= '9'){ x = x * 10 + s - '0'; s = getchar();}
return x *= f;
}

inline void push_up(int rt){ tree[rt] = tree[rt << 1] + tree[rt << 1 | 1]; }

inline void push_down(int rt, int m){
if(lazy[rt]){
lazy[rt << 1] += lazy[rt], lazy[rt << 1 | 1] += lazy[rt];
tree[rt << 1] += lazy[rt] * (m - (m >> 1));
tree[rt << 1 | 1] += lazy[rt] * (m >> 1);
lazy[rt] = 0;
}
}

void build(int rt, int l, int r){
lazy[rt] = 0, tree[rt] = r - l + 1;
if(l == r){
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
push_up(rt);
}

void update(int rt, int l, int r, int L, int R, int val){
if(l >= L && r <= R){
lazy[rt] += val;
tree[rt] += (r - l + 1) * val;
return;
}
int mid = l + r >> 1;
push_down(rt, r - l + 1);
if(mid >= L) update(rt << 1, l, mid, L, R, val);
if(mid < R) update(rt << 1 | 1, mid + 1, r, L, R, val);
push_up(rt);
}

int query(int rt, int l, int r, int L, int R){
if(l >= L && r <= R) return tree[rt];
int mid = l + r >> 1, ans = 0;
push_down(rt, r - l + 1);
if(mid >= L) ans += query(rt << 1, l, mid, L, R);
if(mid < R) ans += query(rt << 1 | 1, mid + 1, r, L, R);
return ans;
}

int stk[N], top;
bool check(int l, int r){
top = 0;
for(int i = l; i <= r; i++)
for(int j = 1; j <= cnt[i]; j++) stk[++top] = d[i][j];
sort(stk + 1, stk + 1 + top);
for(int i = 2; i <= top - 1; i++)
if (stk[i - 1] + stk[i] > stk[i + 1]) return 1;

return 0;
}
vector<int> vec;
signed main(){
cin >> n >> m;
for(int i = 1; i <= n; i++) scanf("%d", &d[i][++cnt[i]]), S.insert(i);
build(1, 1, n);
for(int i = 1; i <= m; i++){
string op; cin >> op;
int l, r, x;
if(op[0] == 'A'){
cin >> l >> r;
ll tmp = query(1, 1, n, l, r);
if(tmp >= 60) puts("YES");
else{
if(check(l, r)) puts("YES");
else puts("NO");
}
}
else{
cin >> l >> r >> x;
update(1, 1, n, l, r, 1);
vec.clear();
auto p = S.lower_bound(l);
while (p != S.end() && *p <= r)
{
int now = *p;
d[now][++cnt[now]] = x;
if (cnt[now] >= 60) vec.push_back(now);
p++;
}
for (auto item : vec) S.erase(item);
}
}
return 0;
}