// segment_tree {{{
#include <vector>
#include <cassert>
template<typename T, typename AssociativeOperation>
struct segment_tree {
int SZ;
T identity;
AssociativeOperation TT;
std::vector<T> data;
segment_tree() {}
segment_tree(int _SZ, T _identity, AssociativeOperation _TT)
: SZ(_SZ), identity(_identity), TT(_TT) {
data.resize(2 * SZ, identity);
}
// Returns the value at index i
const T& operator[](int i) const {
assert(0 <= i && i < SZ);
return data[SZ + i];
}
// Assigns fn(i) at index i for each i in [0, SZ)
template<typename Function>
void assign(Function fn) {
for (int i = 0; i < SZ; i++)
data[SZ + i] = fn(i);
for (int i = SZ - 1; i; i--)
data[i] = TT(data[2 * i], data[2 * i + 1]);
}
// Assigns v at index i
void assign(int i, T v) {
assert(0 <= i && i < SZ);
data[i += SZ] = v;
for (i /= 2; i; i /= 2)
data[i] = TT(data[2 * i], data[2 * i + 1]);
}
// Returns the result of a left fold of the elements at indices in [first, last) over TT
T accumulate(int first, int last) const {
assert(0 <= first && last <= SZ);
T left = identity, right = identity;
for (first += SZ, last += SZ; first < last; first /= 2, last /= 2) {
if (first & 1) left = TT(left, data[first++]);
if (last & 1) right = TT(data[--last], right);
}
return TT(left, right);
}
};
// }}}
// {{{ data_structures/segment_tree.cpp }}}
#include <cassert>
template<typename T, typename BinaryOperation>
struct searchable_segment_tree : segment_tree<T, BinaryOperation> {
using segment_tree<T, BinaryOperation>::SZ;
using segment_tree<T, BinaryOperation>::identity;
using segment_tree<T, BinaryOperation>::TT;
using segment_tree<T, BinaryOperation>::data;
searchable_segment_tree() {}
// Rounds up internal size to the nearest power of 2 to enable binary search
searchable_segment_tree(int _SZ, T _identity, BinaryOperation _TT) :
segment_tree<T, BinaryOperation>(1 << (32 - __builtin_clz(_SZ - 1)), _identity, _TT) {}
/* Returns the smallest index "last" such that p(accumulate(first, last))
* returns true. Returns SZ + 1 if no such index exists. Requires that
* p(accumulate(first, last)) is non-decreasing as last increases.
*/
template<typename Predicate>
int binary_search(int first, Predicate p) const {
assert(0 <= first && first <= SZ);
if (p(identity))
return first;
first += SZ;
T accumulator = identity;
auto try_extend = [&](int bit) {
assert(__builtin_ctz(first) >= bit);
if (first + (1 << bit) > 2 * SZ)
return false;
T extended = TT(accumulator, data[first >> bit]);
if (p(extended))
return false;
accumulator = extended;
first += 1 << bit;
return true;
};
int bit = 0;
while (!(first & (1 << bit)) || try_extend(bit))
bit++;
while (--bit >= 0)
try_extend(bit);
return first - SZ + 1;
}
};
#include <iostream>
#include <climits>
using namespace std;
// {{{ data_structures/searchable_segment_tree }}}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int N, Q;
cin >> N >> Q;
auto smaller = [](int a, int b) { return min(a, b); };
searchable_segment_tree<int, decltype(smaller)> sst(N, INT_MAX, smaller);
for (int q = 0; q < Q; q++) {
char op;
int x, y;
cin >> op >> x >> y;
if (op == 'M') {
sst.assign(y - 1, x);
} else {
int ans = sst.binary_search(y - 1, [&x](int v) { return v <= x; });
cout << (ans > N ? -1 : ans) << "\n";
}
}
return 0;
}
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
1 ms |
364 KB |
Output is correct |
2 |
Correct |
1 ms |
364 KB |
Output is correct |
3 |
Correct |
2 ms |
492 KB |
Output is correct |
4 |
Correct |
109 ms |
6892 KB |
Output is correct |
5 |
Correct |
86 ms |
5484 KB |
Output is correct |
6 |
Correct |
98 ms |
6764 KB |
Output is correct |
7 |
Correct |
109 ms |
6892 KB |
Output is correct |