제출 #1347170

#제출 시각아이디문제언어결과실행 시간메모리
1347170model_codeLegendary Dango Eater (JOI26_dango)C++20
100 / 100
1090 ms182164 KiB
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// range chmin
// point get
struct dual_segmenttree{
    private:
    int n;
    vector<int> node;

    public:
    dual_segmenttree() = default;

    dual_segmenttree(int _n, vector<int> &init){
        n = 1;
        while(n < _n){
            n *= 2;
        }
        node.resize(2 * n, 1e9);
        for(int i = 0; i < _n; i++){
            node[n + i] = init[i];
        }
    }

    // [l, r) <- chmin(val)
    void update(int l, int r, int val){
        l += n;
        r += n;
        while(l < r){
            if(l % 2 == 1){
                node[l] = min(node[l], val);
                l++;
            }
            if(r % 2 == 1){
                r--;
                node[r] = min(node[r], val);
            }
            l >>= 1;
            r >>= 1;
        }
        return;
    }

    int get(int pos){
        pos += n;
        int res = 1e9;
        while(pos >= 1){
            res = min(res, node[pos]);
            pos >>= 1;
        }
        return res;
    }
};

vector<int> find_naive(int n, long long k, vector<long long> &a){
    vector<int> res(n, n);
    for(int i = 0; i < n; i++){
        long long s = 0;
        if(a[i] < 0){
            res[i] = i + 1;
            continue;
        }
        for(int j = i; j < n; j++){
            if(a[j] > 0){
                s += a[j];
                s %= k;
            }
            else{
                if(s + a[j] <= 0){
                    res[i] = j;
                    break;
                }
                s += a[j];
            }
        }
    }
    return res;
}

vector<int> find_right(int n, long long k, vector<long long> &a){
    vector<long long> s(n + 1, 0);
    for(int i = 0; i < n; i++){
        s[i + 1] = s[i] + a[i];
        s[i + 1] %= k;
        if(s[i + 1] < 0){
            s[i + 1] += k;
        }
    }
    vector<pair<long long, int>> v;
    for(int i = 0; i < n + 1; i++){
        v.emplace_back(s[i], i);
    }
    sort(v.begin(), v.end());
    vector<int> inv(n + 1), init(n + 1, n);
    for(int i = 0; i < n + 1; i++){
        inv[v[i].second] = i;
    }
    dual_segmenttree seg(n + 1, init);

    vector<int> res(n, n);
    for(int i = n - 1; i >= 0; i--){
        if(a[i] > 0){
            res[i] = seg.get(inv[i]);
            continue;
        }
        res[i] = i + 1;
        if(-a[i] >= k){
            seg.update(0, n + 1, i);
            continue;
        }
        long long left = (s[i] + a[i] + k) % k, right = s[i];
        // [left, right]
        
        // [l, r]
        auto work = [&](long long l, long long r){
            pair<long long, int> tar = {l, -1};
            int idx_l = lower_bound(v.begin(), v.end(), tar) - v.begin();
            tar = {r + 1, -1};
            int idx_r = lower_bound(v.begin(), v.end(), tar) - v.begin();
            seg.update(idx_l, idx_r, i);
            return;
        };

        if(left <= right){
            work(left, right);
        }
        else{
            work(left, k - 1);
            work(0, right);
        }
    }
    return res;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, q;
    long long k;
    cin >> n >> q >> k;

    int lg = 20;

    vector<long long> a(n);
    vector<long long> sum(n + 1, 0);
    for(int i = 0; i < n; i++){
        cin >> a[i];
        if(i % 2 == 1){
            a[i] *= -1;
        }
        sum[i + 1] = sum[i] + a[i];
    }

    vector<int> right = find_right(n, k, a);

    auto make_doubling = [&](vector<long long> &sum, vector<int> &right){
        vector<vector<pair<int, long long>>> res(lg, vector<pair<int, long long>>(n));
        for(int i = 0; i < n; i++){
            res[0][i] = {right[i], max(0LL, sum[right[i]] - sum[i]) / k};
        }
        for(int j = 1; j < lg; j++){
            for(int i = 0; i < n; i++){
                auto [pos, val] = res[j - 1][i];
                if(pos == n){
                    res[j][i] = res[j - 1][i];
                    continue;
                }
                auto [pos2, val2] = res[j - 1][pos];
                res[j][i] = {pos2, val + val2};
            }
        }
        return res;
    };

    auto doubling = make_doubling(sum, right);

    auto calc = [&](int l, int r, vector<vector<pair<int, long long>>> &doubling, vector<long long> &sum){
        long long res = 0;
        int pos = l;
        for(int j = lg - 1; j >= 0; j--){
            auto [nxt, val] = doubling[j][pos];
            if(nxt <= r){
                res += val;
                pos = nxt;
            }
            if(pos == r){
                break;
            }
        }
        res += max(0LL, sum[r] - sum[pos]) / k;
        return res;
    };

    auto naive = [&](int l, int r, vector<long long> &val){
        long long res = 0;
        long long s = 0;
        for(int i = l; i < r; i++){
            s += val[i];
            s = max(0LL, s);
            res += s / k;
            s %= k;
        }
        return res;
    };

    for(int i = 0; i < q; i++){
        int l, r;
        cin >> l >> r;
        l--;

        if(l % 2 == 1){
            l++;
        }
        if(l == r){
            cout << 0 << "\n";
        }
        else{
            cout << calc(l, r, doubling, sum) << "\n";
        }
    }
}
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...