Balkan OI 2015 - Happiness

Authors: Andi Qu, Benjamin Qi

Isn't it convenient how the problem statement tells us what we have to do? (Try to prove the necessary condition described in the statement yourself.)

We need a data structure that supports the following:

  • Insert numbers into a multiset MM.
  • Erase numbers from MM.
  • Check whether there exists some number x<iMix < \sum_{i \in M} i such that iM,ixi<x\sum_{i \in M, i \leq x}i < x.

Solution 1 - Sparse Segment Tree

Since we want to handle range queries with updates, the obvious option would be to use a BIT or segment tree.

However, the numbers that we want to insert can get very large (up to 101210^{12}). Since we have to answer queries online, using a BIT is out of the question.

Luckily, we can simply use a sparse segment tree instead!

We still need to find a way to check whether the xx described above exists though.

The key observation is that if we know that

kiM,ikik \leq \sum_{i \in M, i \leq k}i

for some kk, then we also know that

liM,ilil \leq \sum_{i \in M, i \leq l}i

for all l(k,iM,iki]l \in (k, \sum_{i \in M, i \leq k}i]. This is true because

liM,ikiiM,ilil \leq \sum_{i \in M, i \leq k}i \leq \sum_{i \in M, i \leq l}i

This means that the next number we need to check is iM,iki+1\sum_{i \in M, i \leq k}i + 1.

If we choose the numbers that we check this way, then we will only check O(log1012)\mathcal{O}(\log 10^{12}) numbers for each query (since the ii-th number we check is always at least 2i12^i - 1).

The complexity of this algorithm is thus O(KQlog21012)\mathcal{O}(KQ \log^2 10^{12}).

Code

#include "happiness.h"
struct Node {
long long l, r, val;
Node *lc, *rc;
Node(long long L, long long R)
: l(L), r(R), val(0), lc(nullptr), rc(nullptr) {}
void update(long long p, long long v) {

Solution 2 - Buckets

A smarter solution is to split the elements of MM into the buckets [2i,2i+1)[2^i, 2^{i + 1}) for each ii from 0 to log1012\log 10^{12}. Notice how there are exactly log1012+1\log 10^{12} + 1 buckets.

Why is this convenient?

Firstly, only the two least elements in each bucket could potentially be bad (since (2k+a)+(2k+b)2k+1(2^k + a) + (2^k + b) \geq 2^{k + 1}). This narrows down the number of elements we need to check significantly.

Secondly, we can store the sum of the elements in each bucket and be able to find the prefix sums of buckets in O(log1012)\mathcal{O}(\log 10^{12}) time.

We can use multisets to store the elements in the buckets, so the complexity of this algorithm is O(KQ(log1012+logKQ))\mathcal{O}(KQ (\log 10^{12} + \log KQ)). In practice, this solution runs faster than the first solution.

Code

#include "happiness.h"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
multiset<ll> todo[40];
ll SUM[40];
void ad(ll x, int b) {

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!