QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#336614 | #8276. Code Congestion | ucup-team1191# | WA | 1ms | 3816kb | C++20 | 22.1kb | 2024-02-24 18:24:14 | 2024-02-24 18:24:14 |
Judging History
answer
#include <bits/stdc++.h>
#define fr first
#define sc second
#define all(a) (a).begin(), (a).end()
#define unique(a) a.resize(unique(a.begin(), a.end()) - a.begin())
using namespace std;
#ifdef ONPC
mt19937 rnd(223);
#else
mt19937 rnd(chrono::high_resolution_clock::now()
.time_since_epoch().count());
#endif
#define TIME (clock() * 1.0 / CLOCKS_PER_SEC)
using ll = long long;
using ld = double;
const int maxn = 5e5 + 100, inf = 1e9 + 100;
void slow() {
const int BIG = 1e9;
const ll INF = 1e12;
const int N = 5;
const int X = 100;
mt19937 rnd(239);
for (int test = 0; test < 1000; test++) {
int n = rnd() % N + 1;
vector<int> h(n);
for (int i = 0; i < n; i++) {
h[i] = rnd() % X + 1;
}
vector<vector<pair<int, int>>> dp(n, vector<pair<int, int>>(2, make_pair(-BIG, BIG)));
for (int i = 1; i < n; i++) {
for (int bit = 0; bit < 2; bit++) {
vector<pair<int, int>> segs;
if (bit == 0 && h[i - 1] < h[i]) {
segs.emplace_back(dp[i - 1][bit]);
} else if (bit == 1 && h[i - 1] > h[i]) {
segs.emplace_back(dp[i - 1][bit]);
}
if (bit == 0) {
auto seg = dp[i - 1][bit ^ 1];
seg.second = min(seg.second, h[i] + h[i - 1]);
if (seg.second >= seg.first) {
segs.emplace_back(seg);
}
} else {
auto seg = dp[i - 1][bit ^ 1];
seg.first = max(seg.first, h[i] + h[i - 1]);
if (seg.second >= seg.first) {
segs.emplace_back(seg);
}
}
if (segs.empty()) {
dp[i][bit] = make_pair(0, -1);
} else if (segs.size() == 1) {
dp[i][bit] = segs[0];
} else {
if (segs[0] > segs[1]) {
swap(segs[0], segs[1]);
}
if (segs[0].second + 1 < segs[1].first) {
cout << n << "\n";
for (int x : h) {
cout << x << " ";
}
cout << "\n";
exit(0);
}
assert(segs[0].second + 1 >= segs[1].first);
dp[i][bit] = make_pair(min(segs[0].first, segs[1].first), max(segs[0].second, segs[1].second));
}
}
}
}
}
namespace segtree {
// This implementation is disgusting, but it seems to work and do it faster than previous version.
template<typename Item>
Item tree_merge(const Item& a, const Item& b) {
Item i;
i.update(a, b);
return i;
}
template<typename Item, bool lazy>
struct Pusher {};
template<typename Item>
struct Pusher<Item, false> {
void push(const vector<Item>&, int, int, int) {}
Item ask_on_segment(const vector<Item>& tree, int n, int l, int r) {
l |= n;
r |= n;
Item resl, resr;
while (l <= r) {
if (l & 1) {
resl = tree_merge(resl, tree[l]);
++l;
}
if (!(r & 1)) {
resr = tree_merge(tree[r], resr);
--r;
}
l >>= 1;
r >>= 1;
}
return tree_merge(resl, resr);
}
void push_point(const vector<Item>&, int, int) {}
template<typename P>
int lower_bound(const vector<Item>& tree, int n, int l, P p) {
Item cur;
if (p(cur)) return l - 1;
l |= n;
int r = n | (n - 1);
// carefully go up
while (true) {
if (p(tree_merge(cur, tree[l]))) {
break;
}
if (l == r) return n;
if (l & 1) {
cur = tree_merge(cur, tree[l]);
++l;
}
l >>= 1;
r >>= 1;
}
// usual descent from l
while (l < n) {
if (p(tree_merge(cur, tree[l * 2]))) {
l = l * 2;
} else {
cur = tree_merge(cur, tree[l * 2]);
l = l * 2 + 1;
}
}
return (l ^ n);
}
template<typename P>
int lower_bound_rev(const vector<Item>& tree, int n, int r, P p) {
Item cur;
if (p(cur)) return r + 1;
r |= n;
int l = n;
// carefully go up
while (true) {
if (p(tree_merge(tree[r], cur))) {
break;
}
if (l == r) return -1;
if (!(r & 1)) {
cur = tree_merge(tree[r], cur);
--r;
}
l >>= 1;
r >>= 1;
}
// usual descent from r
while (r < n) {
if (p(tree_merge(tree[r * 2 + 1], cur))) {
r = r * 2 + 1;
} else {
cur = tree_merge(tree[r * 2 + 1], cur);
r = r * 2;
}
}
return (r ^ n);
}
};
template<typename Item>
struct Pusher<Item, true> {
void push(vector<Item>& tree, int ind, int l, int r) {
tree[ind].push(tree[ind * 2], tree[ind * 2 + 1], l, r);
}
Item ask_on_segment(vector<Item>& tree, int n, int l, int r) {
int vl = 0, vr = n - 1;
int i = 1;
Item result;
while (vl != vr) {
int m = (vl + vr) / 2;
if (l > m) {
push(tree, i, vl, vr);
i = i * 2 + 1;
vl = m + 1;
} else if (r <= m) {
push(tree, i, vl, vr);
i = i * 2;
vr = m;
} else {
break;
}
}
if (l == vl && r == vr) {
return tree[i];
}
push(tree, i, vl, vr);
// left
{
int ind = i * 2;
int L = vl, R = (vl + vr) / 2;
while (l != L) {
int m = (L + R) / 2;
push(tree, ind, L, R);
if (l <= m) {
result = tree_merge(tree[ind * 2 + 1], result);
ind *= 2;
R = m;
} else {
ind = ind * 2 + 1;
L = m + 1;
}
}
result = tree_merge(tree[ind], result);
}
// right
{
int ind = i * 2 + 1;
int L = (vl + vr) / 2 + 1, R = vr;
while (r != R) {
int m = (L + R) / 2;
push(tree, ind, L, R);
if (r > m) {
result = tree_merge(result, tree[ind * 2]);
ind = ind * 2 + 1;
L = m + 1;
} else {
ind = ind * 2;
R = m;
}
}
result = tree_merge(result, tree[ind]);
}
return result;
}
void push_point(vector<Item>& tree, int n, int ind) {
int l = 0, r = n - 1;
int i = 1;
while (l != r) {
push(tree, i, l, r);
int m = (l + r) / 2;
if (ind <= m) {
r = m;
i *= 2;
} else {
l = m + 1;
i = i * 2 + 1;
}
}
}
template<typename P>
pair<int, Item> _lower_bound(vector<Item>& tree, int l, P p, Item cur, int i, int vl, int vr) {
if (vl == vr) {
if (p(tree_merge(cur, tree[i]))) {
return {vl, tree[i]};
} else {
return {vl + 1, tree[i]};
}
}
push(tree, i, vl, vr);
int m = (vl + vr) / 2;
if (l > m) {
return _lower_bound(tree, l, p, cur, i * 2 + 1, m + 1, vr);
} else if (l <= vl) {
if (!p(tree_merge(cur, tree[i]))) {
return {vr + 1, tree_merge(cur, tree[i])};
}
if (p(tree_merge(cur, tree[i * 2]))) {
return _lower_bound(tree, l, p, cur, i * 2, vl, m);
} else {
return _lower_bound(tree, l, p, tree_merge(cur, tree[i * 2]), i * 2 + 1, m + 1, vr);
}
} else {
auto [ind, it] = _lower_bound(tree, l, p, cur, i * 2, vl, m);
if (ind <= m) return {ind, it};
return _lower_bound(tree, l, p, it, i * 2 + 1, m + 1, vr);
}
}
template<typename P>
int lower_bound(vector<Item>& tree, int n, int l, P p) {
Item cur;
if (p(cur)) return l - 1;
return _lower_bound(tree, l, p, cur, 1, 0, n - 1).first;
}
template<typename P>
pair<int, Item> _lower_bound_rev(vector<Item>& tree, int r, P p, Item cur, int i, int vl, int vr) {
if (vl == vr) {
if (p(tree_merge(tree[i], cur))) {
return {vl, tree[i]};
} else {
return {vl - 1, tree[i]};
}
}
push(tree, i, vl, vr);
int m = (vl + vr) / 2;
if (r <= m) {
return _lower_bound_rev(tree, r, p, cur, i * 2, vl, m);
} else if (r >= vr) {
if (!p(tree_merge(tree[i], cur))) {
return {vl - 1, tree_merge(cur, tree[i])};
}
if (p(tree_merge(tree[i * 2 + 1], cur))) {
return _lower_bound_rev(tree, r, p, cur, i * 2 + 1, m + 1, vr);
} else {
return _lower_bound_rev(tree, r, p, tree_merge(tree[i * 2 + 1], cur), i * 2, vl, m);
}
} else {
auto [ind, it] = _lower_bound_rev(tree, r, p, cur, i * 2 + 1, m + 1, vr);
if (ind > m) return {ind, it};
return _lower_bound_rev(tree, r, p, it, i * 2, vl, m);
}
}
template<typename P>
int lower_bound_rev(vector<Item>& tree, int n, int r, P p) {
Item cur;
if (p(cur)) return r + 1;
return _lower_bound_rev(tree, r, p, cur, 1, 0, n - 1).first;
}
};
template<typename Item, bool lazy = false>
struct Segtree {
vector<Item> tree;
Pusher<Item, lazy> pusher;
int n;
int n0;
Segtree(int n = 0) {
build(n);
}
template<typename U>
Segtree(const vector<U>& v) {
build(v);
}
void build(int n) {
this->n0 = n;
while (n & (n - 1)) ++n;
this->n = n;
tree.assign(n * 2, {});
}
template<typename U>
void build(const vector<U>& v) {
build(v.size());
for (int i = 0; i < v.size(); ++i) {
tree[n | i].init(v[i], i);
}
build();
}
void build() {
for (int i = n - 1; i >= 1; --i) {
tree[i].update(tree[i * 2], tree[i * 2 + 1]);
}
}
void push(int ind, int l, int r) {
pusher.push(tree, ind, l, r);
}
template<typename T>
void set(int ind, const T& t) {
pusher.push_point(tree, n, ind);
ind |= n;
tree[ind].init(t, ind ^ n);
ind >>= 1;
while (ind) {
tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]);
ind >>= 1;
}
}
template<typename T>
void update(int ind, const T& t) {
pusher.push_point(tree, n, ind);
ind |= n;
tree[ind].update(t, ind ^ n);
ind >>= 1;
while (ind) {
tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]);
ind >>= 1;
}
}
Item& ith(int ind) {
static_assert(!lazy, "don't use this method with lazy propagation, unless you're sure you need it");
return tree[ind | n];
}
const Item& root() const {
return tree[1];
}
Item ask(int l, int r) {
l = max(l, 0);
r = min(r, n - 1);
if (l > r) return {};
return pusher.ask_on_segment(tree, n, l, r);
}
template<typename T>
void modify(int l, int r, const T& t) {
static_assert(lazy, "lazy must be set to true to use this function");
l = max(l, 0);
r = min(r, n - 1);
if (l > r) return;
int vl = 0, vr = n - 1;
int i = 1;
while (vl != vr) {
int m = (vl + vr) / 2;
if (l > m) {
push(i, vl, vr);
i = i * 2 + 1;
vl = m + 1;
} else if (r <= m) {
push(i, vl, vr);
i = i * 2;
vr = m;
} else {
break;
}
}
if (l == vl && r == vr) {
tree[i].modify(t, l, r);
} else {
push(i, vl, vr);
// left
{
int ind = i * 2;
int L = vl, R = (vl + vr) / 2;
while (l != L) {
int m = (L + R) / 2;
push(ind, L, R);
if (l <= m) {
tree[ind * 2 + 1].modify(t, m + 1, R);
ind *= 2;
R = m;
} else {
ind = ind * 2 + 1;
L = m + 1;
}
}
tree[ind].modify(t, L, R);
ind >>= 1;
while (ind != i) {
tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]);
ind >>= 1;
}
}
// right
{
int ind = i * 2 + 1;
int L = (vl + vr) / 2 + 1, R = vr;
while (r != R) {
int m = (L + R) / 2;
push(ind, L, R);
if (r > m) {
tree[ind * 2].modify(t, L, m);
ind = ind * 2 + 1;
L = m + 1;
} else {
ind = ind * 2;
R = m;
}
}
tree[ind].modify(t, L, R);
ind >>= 1;
while (ind != i) {
tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]);
ind >>= 1;
}
}
tree[i].update(tree[i * 2], tree[i * 2 + 1]);
}
i >>= 1;
while (i) {
tree[i].update(tree[i * 2], tree[i * 2 + 1]);
i >>= 1;
}
}
// first index r such that p(tree.ask(l, r)) == true
// if p() is true for empty item, return l-1
// if p() is never true, returns n
template<typename P>
int lower_bound(int l, P p) {
l = max(l, 0);
if (l >= n0) return n0;
return min(n0, pusher.lower_bound(tree, n, l, p));
}
// similarly to lower_bound, returns first (largest) l such that p(tree.ask(l, r)) == true
template<typename P>
int lower_bound_rev(int r, P p) {
r = min(r, n0 - 1);
if (r < 0) return -1;
return pusher.lower_bound_rev(tree, n, r, p);
}
};
}
using segtree::Segtree;
struct Item {
bool d[2][2];
Item() {
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
d[i][j] = 1;
}
template<typename T>
void init(const T& t, int ind) {
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
d[i][j] = 1;
}
void update(const Item& a, const Item& b) {
memset(d, 0, sizeof(d));
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
if (a.d[i][j])
for (int k = 0; k < 2; k++)
if (b.d[j][k])
d[i][k] = 1;
}
//// similar to init, but more convenient for doing a[i] += x, implement only if needed
template<typename T>
void update(const T& t, int ind) {
d[t.fr.fr][t.fr.sc] = t.sc;
}
//// apply here, save for children
// template<typename T>
// void modify(const T& m, int l, int r) {}
// void push(Item& a, Item& b, int l, int r) {
// int m = (l + r) / 2;
// a.modify(mod, l, m);
// b.modify(mod, m + 1, r);
// // reset mod
// }
};
/*
// first index r such that p(tree.ask(l, r)) == true
// if p() is true for empty item, return l-1
// if p() is never true, returns n
template<typename P>
int lower_bound(int l, P p) {
l = max(l, 0);
if (l >= n0) return n0;
return min(n0, pusher.lower_bound(tree, n, l, p));
}
// similarly to lower_bound, returns first (largest) l such that p(tree.ask(l, r)) == true
template<typename P>
int lower_bound_rev(int r, P p) {
r = min(r, n0 - 1);
if (r < 0) return -1;
return pusher.lower_bound_rev(tree, n, r, p);
}
*/
void solve() {
int n;
cin >> n;
vector<ll> a(n);
for (ll &i : a)
cin >> i;
vector<pair<ll, int>> g;
Segtree<Item> t(n);
auto dai = [&](int x, int y, int w) {
return make_pair(make_pair(x, y), w);
};
for (int i = 0; i + 1 < n; i++) {
if (a[i] < a[i + 1]); else
t.update(i, dai(0, 0, 0));
if (a[i] > a[i + 1]); else
t.update(i, dai(1, 1, 0));
g.push_back({a[i] + a[i + 1], i});
t.update(i, dai(0, 1, 0));
}
sort(all(g));
vector<pair<int, int>> che;
auto pred = [&](Item const &w) -> bool {
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
if (w.d[i][j])
return 0;
return 1;
};
auto print = [&]() {
for (int i = 0; i < n - 1; i++) {
auto w = t.ask(i, i);
for (int x = 0; x < 2; x++)
for (int y = 0; y < 2; y++)
cerr << w.d[x][y];
cerr << ' ';
}
cerr << '\n';
};
print();
for (int i = 0; i < n; i++) {
int r = t.lower_bound(i, pred);
r--;
if (r > i) {
cerr << "i " << i << ' ' << r << '\n';
che.push_back({i, r});
}
}
int L = 0;
while (L < g.size()) {
int R = L;
vector<int> pos;
while (R < g.size() && g[R].fr == g[L].fr) {
int i = g[R].sc;
R++;
t.update(i, dai(0, 1, 1));
t.update(i, dai(1, 0, 0));
pos.push_back(i);
}
cerr << "done " << g[L].fr << '\n';
L = R;
print();
{
// edge 0->1
for (int i : pos) {
auto p2 = [&](Item const &w) -> bool {
return w.d[1][0] == 0 && w.d[1][1] == 0;
};
auto p1 = [&](Item const &w) -> bool {
return w.d[0][0] == 0 && w.d[1][0] == 0;
};
int r = t.lower_bound(i + 1, p2);
int l = t.lower_bound_rev(i - 1, p1);
l++;
if (l < r) {
cerr << "ad " << l << ' ' << r << '\n';
che.push_back({l, r});
}
}
}
}
vector<vector<int>> op(n);
vector<vector<int>> cl(n);
for (auto [l, r] : che) {
l = max(0, l);
r = min(n - 1, r);
if (l >= r)
continue;
op[l].push_back(r);
cl[r].push_back(r);
}
multiset<int> q;
ll ans = 0;
for (int i = 0; i < n; i++) {
for (int w : op[i])
q.insert(w);
if (!q.empty()) {
int r = *q.rbegin();
ans += r - i;
}
for (int w : cl[i])
q.erase(q.find(w));
}
cout << ans << '\n';
}
int main() {
#ifdef ONPC
freopen("../a.in", "r", stdin);
// freopen("../a.out", "w", stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
cout << fixed;
cout.precision(20);
solve();
cerr << "\n\nConsumed " << TIME << endl;
}
/*
C:\Users\ramil\Desktop\trenirovka\waterloo\ucups\2nd\tmp\cmake-build-debug\tmp.exe
3
1111 1111
i 1 2
done 2
1111 1111
ad 0 3
ad 0 3
Consumed 0.015
Process finished with exit code 0
*/
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 0
Wrong Answer
time: 1ms
memory: 3816kb
input:
3 3 2 3 4 1 2 2
output:
3
result:
wrong answer 1st numbers differ - expected: '40', found: '3'