Submission #75060

#TimeUsernameProblemLanguageResultExecution timeMemory
75060dacin21Meetings (IOI18_meetings)C++14
100 / 100
4239 ms353996 KiB
// 100 p
#undef _GLIBCXX_DEBUG
#include <bits/stdc++.h>

#ifdef LOCAL_RUN
#include "prettyprint.hpp"
#endif // LOCAL_RUN


#define debug(x) do{}while(0)

using namespace std;

using ll = long long;
template<typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
constexpr int inf = 1e9;

// could maybe be optimized by transposing
template<typename T = int, typename comp = greater<T>>
class Sparsetable{
    int compind(int i, int j, int l, int sign)const{
        i = RMQ[lgn*i+l], j=RMQ[lgn*(j+sign*(1<<l))+l];
        return comp()(data[i], data[j])? i : j;
    }
    int minind(int l, int r)const{
		assert(l<r);
        return compind(l, r, lg2[r-l],-1);
    }
    void build(){
        lg2.resize(n+1);
        for(int i=2;i<=n;++i) lg2[i]=1+lg2[i/2];
        lgn = lg2.back()+1;
        RMQ.resize(n*lgn);
        for(int i=n-1;i>=0;--i){
            RMQ[lgn*i]=i;
            for(int j=0;j<lg2[n-i];++j) RMQ[lgn*i+j+1] = compind(i,i,j,1);
        }
    }
    public:
    Sparsetable(T const*v, int _N):n(_N), data(v, v+_N){build();}
    Sparsetable(vector<T> const&v):Sparsetable(v.data(), v.size()){};
    // min in [l, r)
    pair<int, T&> operator()(int const&i, int const&j){
        int k = minind(i, j);
        return pair<int, T&>(k, data[k]);
    }
    int n, lgn;
    vector<int> RMQ, lg2;
    vector<T> data;
};


struct Node{
    int l_size, r_size;
    pair<int, int> val;
    ll l_dp, r_dp, dp;
    int get_size(){return l_size + r_size + 1;}
    void recalc_dp(){
        ll cand1 = l_dp + (r_size+1)*(ll)val.first;
        ll cand2 = r_dp + (l_size+1)*(ll)val.first;
        dp = min(cand1, cand2);
    }
};

int n, q;

vector<pair<int, int> > calc_maxval(vector<pair<int, int>> const&H, vector<int> const&L, vector<int> const&R){
    Sparsetable<pair<int, int> > s(H);
    vector<pair<int, int>> ret(q);
    for(int i=0;i<q;++i){
        ret[i] = s(L[i], R[i]+1).second;
    }
    return ret;
}

struct Block{
    struct Node{
        pair<int, int> val;
        ll dp_base;
        int l_size;
        ll l_add() const {
            return (l_size+1)*(ll)val.first;
        }
        bool operator<(pair<int, int> const&o) const {
            return val < o;
        }
        bool operator>(pair<int, int> const&o) const {
            return val > o;
        }

        friend ostream& operator<<(ostream&o, Node const&n){
#ifdef LOCAL_RUN
            return o << n.val << " " << n.dp_base << " " << n.l_size;
#else
            return o;
#endif
        }
    };
    deque<Node> nodes;
    ll a, b;// globally add a*x+b
    // returns (r_dp of max, index of max)
    Block(){}
    Block(Node const&n, ll a_, ll b_):nodes(1, n), a(a_), b(b_){}
    pair<ll, int> query(pair<int, int> const&val, int t){
        debug(cerr << "Query " << (*this)  << "  " << val << " " << t << "\n");
        auto it = lower_bound(nodes.begin(), nodes.end(), val, std::greater<>());
        assert(it != nodes.end() && it->val == val);
        const int index = it->val.second;
        ++it;
        // dp_r is in next block
        if(it == nodes.end()){
            return make_pair(-1, index);
        }
        return make_pair(it->dp_base + a*t + b, index);
    }
    ll query_dp_r(int t){
        const Node& n = nodes.front();
        return n.dp_base + a*t + b;
    }
    // TODO: fix
    static Block merge(Block &&l, Block &&r){
        // make l's dp depend on r
        const Node& n1 = l.nodes.back(), n2 = r.nodes.front();
        ll l_new_add = -n1.dp_base + n2.dp_base + n1.l_add() - l.b + r.b;
        l.b += l_new_add;
        l.a = r.a;
        // update dp at back
        Block *a = &l, *b = &r;
        if(a->nodes.size() > b->nodes.size()){
            swap(a, b);
        }
        for(auto &e:a->nodes){
            e.dp_base += (a->b - b->b);
        }
        a->b = b->b;
        if(l.nodes.size() < r.nodes.size()){
            r.nodes.insert(r.nodes.begin(), l.nodes.begin(), l.nodes.end());
            return move(r);
        } else {
            l.nodes.insert(l.nodes.end(), r.nodes.begin(), r.nodes.end());
            return move(l);
        }
    }
    // returns (index, dp)
    pair<int, ll> intersect(pair<int, int> const&val, int dir){
        pair<int, ll> ret(-1, -1);
        while(!nodes.empty() && nodes.back().val <= val){
            const int index = nodes.back().val.second;
            ret = make_pair(index-dir*nodes.back().l_size, nodes.back().dp_base + a*(val.second-dir) + b);
            nodes.pop_back();
        }
        return ret;
    }
    int calc_intersection(Block const&r, bool const& rev){
        const ll m1 = a, q1 = nodes.back().dp_base + b;
        const ll m2 = r.a, q2 = r.nodes.front().dp_base + r.b + nodes.back().l_add();
        debug(cerr << "intersect " << m1 << " " << q1 << " | " << m2 << " " << q2 << "\n");
        if(m1 == m2){
            if(q2 <= q1){ // already intersected
                return rev ? inf : -inf;
            } else { // won't ever intersect
                return rev ? -inf : inf;
            }
        } else {
            // intersection at (q2-q1)/(m1-m2) -> round correctly
            long double tmp = (q2 - q1) / (long double)(m1 - m2);
            if(tmp < -inf) return -inf;
            if(tmp > inf) return inf;
            return rev ? floor(tmp) : ceil(tmp);
        }
    }
    friend ostream& operator<<(ostream&o, Block const&b){

#ifdef LOCAL_RUN
        return o << "Block: " << b.a << "*x + " << b.b << " : " << b.nodes;
#else
        return o;
#endif
    }
};

vector<pair<int, ll> > sweep(vector<pair<int, int>> const&H, vector<pair<int, int>> const&M, vector<int> const&R, bool const rev){
    vector<int> ord(n);
    iota(ord.begin(), ord.end(), 0);
    const int dir = rev ? -1 : 1;
    if(rev){
        reverse(ord.begin(), ord.end());
    }
    vector<vector<int> > ev(n);
    for(int i=0;i<q;++i){
        ev[R[i]].push_back(i);
    }
    map<pair<int, int>, Block> s;
    vector<pair<int, ll> > ret(q);
    min_heap<array<int, 3> > inters;
    auto add_event = [&](map<pair<int, int>, Block>::iterator it){
        assert(it != s.end());
        auto it2 = next(it);
        if(it2 == s.end()) return;
        int inter = it2->second.calc_intersection(it->second, rev);
        inters.push({inter*dir, it->first.first, it->first.second});
    };
    for(auto const&e:ord){
        // add element to cartesian tree
        Block::Node n{H[e], 0, 0};
        auto it = s.begin();
        for(;it != s.end();++it){
            auto tmp = it->second.intersect(H[e], dir);
            if(tmp.first == -1 && tmp.second == -1){
                break;
            }
            n.l_size = abs(e - tmp.first);
            n.dp_base = tmp.second;
        }
        if(it != s.begin()){
            --it;
            s.erase(s.begin(), it);
            if(it->second.nodes.empty()) s.erase(it);
        }
        s[H[e]] = Block(n, n.val.first*dir, -n.val.first*dir * (ll)n.val.second + n.val.first);
        add_event(s.begin());
        // process intersection events

        while(!inters.empty() && inters.top()[0] <= dir*e){
            auto inter = inters.top();
            inters.pop();
            pair<int, int> l = make_pair(inter[1], inter[2]);
            auto it = s.find(l);
            if(it == s.end()) continue;
            auto it2 = next(it);
            if(it2 == s.end()) continue;
            int real_inter = it2->second.calc_intersection(it->second, rev);
            if(inter[0] != real_inter*dir) continue;
            it2->second = Block::merge(move(it2->second), move(it->second));
            s.erase(it);
            add_event(it2);
        }
        debug(cerr << e << " : " << s << "\n");
        // process queries
        for(auto const&f : ev[e]){
            auto it = s.lower_bound(M[f]);
            assert(it != s.end());
            pair<ll, int> ans = it->second.query(M[f], e);
            if(ans.first == -1){
                if(it == s.begin()){
                    ans.first = 0;
                } else {
                    ans.first = prev(it)->second.query_dp_r(e);
                }
            }
            ret[f] = make_pair(abs(e-ans.second), ans.first);
        }
        //cerr << inters << "\n";
    }
    debug(cerr << "sweep\n" << R << "\n" << M << "\n" << ret << "\n");
    return ret;
}

vector<pair<int, ll> > sweep_slow(vector<pair<int, int>> const&H, vector<pair<int, int>> const&M, vector<int> const&R, bool const rev){
    vector<int> ord(n);
    iota(ord.begin(), ord.end(), 0);
    if(rev){
        reverse(ord.begin(), ord.end());
    }
    vector<vector<int> > ev(n);
    for(int i=0;i<q;++i){
        ev[R[i]].push_back(i);
    }
    vector<Node> s;
    vector<pair<int, ll> > ret(q);
    for(auto const&e:ord){
        // add element to cartesian tree
        Node n{0, 0, H[e], 0, 0, H[e].first};
        while(!s.empty() && n.val >= s.back().val){
            n.l_size = s.back().get_size();
            n.l_dp = s.back().dp;
            s.pop_back();
        }
        n.recalc_dp();
        s.push_back(n);
        for(auto it = s.rbegin(), it2=next(it);it2!=s.rend();it = it2, it2 = next(it)){
            ++(it2->r_size);
            it2->r_dp = it->dp;
            it2->recalc_dp();
        }
        // process queries
        for(auto const&f : ev[e]){
            int i=0;
            while(s[i].val > M[f]) ++i;
            assert(s[i].val == M[f]);
            ret[f] = make_pair(s[i].r_size, s[i].r_dp);
        }
    }
    //cerr << "sweep\n" << R << "\n" << M << "\n" << ret << "\n";
    return ret;
}

vector<ll> minimum_costs(vector<int> HH, vector<int> L, vector<int> R){
    assert(L.size() == R.size());
    n = HH.size();
    q = R.size();
    vector<pair<int, int> > H(n);
    for(int i=0;i<n;++i){
        H[i] = make_pair(HH[i], i);
    }
    const vector<pair<int, int> > M = calc_maxval(H, L, R);
    vector<pair<int, ll> > cost_R = sweep(H, M, R, false);
    vector<pair<int, ll> > cost_L = sweep(H, M, L, true);
    vector<ll> ret(q);
    for(int i=0;i<q;++i){
        ll cand1 = M[i].first*(ll)(R[i]-L[i]+1-cost_L[i].first) + cost_L[i].second;
        ll cand2 = M[i].first*(ll)(R[i]-L[i]+1-cost_R[i].first) + cost_R[i].second;
        debug(cerr << cand1 << " / " << cand2 << "\n");
        ret[i] = min(cand1, cand2);
    }
    return ret;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...