HDU 6601 - Keen On Everything But Triangle

题目链接:HDU 6601

首先可以确定为了在线性时间内判断和获取一个可以形成最大三角形的三元组,我们需要获得的是一个已经排序的序列。已经从大到小排序的序列,只有 \(d_i \leq d_{i+1} + d_{i + 2}\) 的时候不能构成三角形,我们考虑最极端的情况,即 \(d_i = d_{i+1} + d_{i+2}\),根据斐波那契数列的性质,最多这个数列会在 45 项内收敛到 0。所以我们只要维护区间前 45 大的数,然后 \(O(45)\) 地判断最大三角形就可以了,这里可以用线段树实现,把 push-up 操作改成归并即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAX_N = 100000 + 5;
const int MT_N = 45;
struct Node {
int mt[MT_N];
int tot;
Node() { tot = 0; }
} tree[MAX_N * 4];
inline int ls(const int &o) {
return o << 1;
}
inline int rs(const int &o) {
return o << 1 | 1;
}
void pushUp(const int &o) {
int *l = tree[ls(o)].mt;
int *r = tree[rs(o)].mt;
int *x = tree[o].mt;
int lTot = tree[ls(o)].tot, rTot = tree[rs(o)].tot;
int lPtr = 0, rPtr = 0, oPtr = 0;
while (oPtr < MT_N) {
if (lPtr < lTot && rPtr < rTot) {
if (l[lPtr] > r[rPtr]) x[oPtr++] = l[lPtr++];
else x[oPtr++] = r[rPtr++];
} else if (lPtr == lTot) {
x[oPtr++] = r[rPtr++];
} else if (rPtr == rTot) {
x[oPtr++] = l[lPtr++];
}
if (lPtr == lTot && rPtr == rTot) break;
}
tree[o].tot = oPtr;
}
void build(int *a, int o, int l, int r) {
if (l == r) {
tree[o].tot = 1;
tree[o].mt[0] = a[l];
return;
}
int mid = (l + r) >> 1;
build(a, ls(o), l, mid);
build(a, rs(o), mid + 1, r);
pushUp(o);
}
Node query(int o, int l, int r, int L, int R) {
if (L <= l && r <= R) {
return tree[o];
}
int mid = (l + r) >> 1;
Node ret, lAns, rAns;
if (L <= mid) lAns = query(ls(o), l, mid, L, R);
if (R > mid) rAns = query(rs(o), mid + 1, r, L, R);
int *lArr = lAns.mt, *rArr = rAns.mt, *x = ret.mt, *oArr = ret.mt;
int lPtr = 0, rPtr = 0, oPtr = 0, lTot = lAns.tot, rTot = rAns.tot;
while (oPtr < MT_N) {
if (lPtr < lTot && rPtr < rTot) {
if (lArr[lPtr] > rArr[rPtr]) x[oPtr++] = lArr[lPtr++];
else x[oPtr++] = rArr[rPtr++];
} else if (lPtr == lTot) {
x[oPtr++] = rArr[rPtr++];
} else if (rPtr == rTot) {
x[oPtr++] = lArr[lPtr++];
}
if (lPtr == lTot && rPtr == rTot) break;
}
ret.tot = oPtr;
return ret;
}
int n, q, a[MAX_N];
int main() {
while (scanf("%d%d", &n, &q) != EOF) {
for (int i = 1; i <= n; ++i) scanf("%d", a + i);
build(a, 1, 1, n);
int u, v;
for (int i = 1; i <= q; ++i) {
scanf("%d%d", &u, &v);
Node t = query(1, 1, n, u, v);
if (t.tot < 3) {
puts("-1");
continue;
} else {
bool ok = false;
LL ans;
for (int j = 2; j < t.tot; ++j) {
if (t.mt[j - 1] > t.mt[j - 2] - t.mt[j]) {
ans = LL(t.mt[j - 1]) + LL(t.mt[j]) + LL(t.mt[j - 2]);
ok = true;
break;
}
}
if (ok) printf("%lld\n", ans);
else puts("-1");
}
}
}
return 0;
}