Cod sursa(job #3123099)

Utilizator fanache99Constantin-Buliga Stefan fanache99 Data 21 aprilie 2023 20:55:50
Problema Arbori de intervale Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 10.44 kb
// https://www.infoarena.ro/problema/arbint
#include <string>
#pragma once

#include <fstream>
#include <iostream>
#include <vector>
#include <filesystem>

template<typename T>
std::istream& operator>>(std::istream &in, std::vector<T> &vec) {
    for (auto &x : vec) {
        in >> x;
    }
    return in;
}

template<typename T>
std::ostream& operator<<(std::ostream &out, const std::vector<T> &vec) {
    for (const auto &x : vec) {
        out << x << " ";
    }
    out << "\n";
    return out;
}

class Reader {
    template<typename T>
    friend Reader& operator>>(Reader &reader, T& t) {
        (*reader.in) >> t;
        return reader;
    }

protected:
    explicit Reader (std::istream *in = nullptr) : in(in) {}
    std::istream *in;
};

class FileReader : public Reader {
public:
    explicit FileReader(const std::string &filename) : fin(filename) {
        in = &fin;
    }

private:
    std::ifstream fin;
};

class StdinReader : public Reader {
public:
    StdinReader() : Reader(&std::cin) {}
};

#ifdef LOCAL_PROJECT

std::string input_path() {
    std::string file = __FILE__;
    std::string directory = file.substr(0, file.rfind('/'));
    return directory + "/input.txt";
}

FileReader cin(input_path());
#else
StdinReader cin;
#endif

#pragma once

#include <optional>
#include <cassert>
#include <memory>
#pragma once

#include <vector>
#include <array>

template<size_t N>
struct StaticSize {
    template<typename T>
    class StaticAllocator {
    public:
        T* allocate(size_t n) {
            offset += n;
            return &data[offset - n];
        }

    private:
        static size_t offset;
        static std::array<T, N> data;
    };
};

template<size_t N>
template<typename T>
size_t StaticSize<N>::StaticAllocator<T>::offset{};

template<size_t N>
template<typename T>
std::array<T, N> StaticSize<N>::StaticAllocator<T>::data{};

template<typename Data, typename Operation, template<typename> typename Allocator = std::allocator>
class SegmentTree {
public:
    explicit SegmentTree(size_t n);

    template<typename T>
    explicit SegmentTree(const std::vector<T> &v);

    template<typename ...Args>
    void update(size_t left, size_t right, Args &&...args);

    Data query(size_t left, size_t right);

private:
    struct Node {
        Node() = default;
        explicit Node(const Data &data, Node *leftSon = nullptr, Node *rightSon = nullptr) :
                data(data), leftSon(leftSon), rightSon(rightSon) {}

        Data data;
        Operation lazy;
        Node *leftSon, *rightSon;
    };

    template<typename ...Args>
    Node *makeNode(Args &&...args);

    template<typename T>
    Node *build(const std::vector<T> &v);

    template<typename T>
    Node *build(const std::vector<T> &v, size_t left, size_t right);

    static size_t getMiddle(size_t left, size_t right);

    void updateImpl(Node *node, size_t left, size_t right, size_t from, size_t to, const Operation &op);

    Data queryImpl(Node *node, size_t left, size_t right, size_t from, size_t to);

    void push(Node *node, size_t left, size_t right);

    bool apply(const Operation &op, Node *node, size_t left, size_t right);

    Allocator<Node> alloc;
    size_t n;
    Node *root;
};

template<typename T>
struct SumData {
    SumData() : sum(0) {}

    template<typename U>
    explicit SumData(const U &u) : sum(u) {}

    SumData(const SumData &left, const SumData &right) : sum(left.sum + right.sum) {}

    T sum;
};

template<typename T>
struct MaxData {
    MaxData() : max(std::numeric_limits<T>::min()) {}

    template<typename U>
    explicit MaxData(const U &u) : max(u) {}

    MaxData(const MaxData &left, const MaxData &right) : max(std::max(left.max, right.max)) {}

    T max;
};

template<typename T>
struct MinData {
    MinData() : min(std::numeric_limits<T>::max()) {}

    template<typename U>
    explicit MinData(const U &u) : min(u) {}

    MinData(const MinData &left, const MinData &right) : min(std::min(left.min, right.min)) {}

    T min;
};

template<typename T>
struct SetOperation {
    SetOperation() = default;
    explicit SetOperation(const T &t) : val(t) {}

    SetOperation(const SetOperation &op1, const SetOperation &op2) : val(op2.val) {}

    bool apply(SumData<T> &data, size_t left, size_t right) const {
        if (val) {
            data.sum = *val * (right - left + 1);
        }
        return true;
    }

    bool apply(MaxData<T> &data, size_t, size_t) const {
        if (val) {
            data.max = *val;
        }
        return true;
    }

    bool apply(MinData<T> &data, size_t, size_t) const {
        if (val) {
            data.min = *val;
        }
        return true;
    }

    std::optional<T> val;
};

template<typename T>
struct AddOperation {
    AddOperation() : add(0) {}
    explicit AddOperation(const T &t) : add(t) {}

    AddOperation(const AddOperation &op1, const AddOperation &op2) : add(op1.add + op2.add) {}

    bool apply(SumData<T> &data, size_t left, size_t right) const {
        data.sum += add * (right - left + 1);
        return true;
    }

    bool apply(MaxData<T> &data, size_t, size_t) const {
        data.max += add;
        return true;
    }

    bool apply(MinData<T> &data, size_t, size_t) const {
        data.min += add;
        return true;
    }

    T add;
};

/* ----------------------------------------------IMPLEMENTATION------------------------------------------------------ */
template<typename Data, typename Operation, template<typename> typename Allocator>
SegmentTree<Data, Operation, Allocator>::SegmentTree(size_t n) : n(n), root(makeNode()) {}

template<typename Data, typename Operation, template<typename> typename Allocator>
template<typename T>
SegmentTree<Data, Operation, Allocator>::SegmentTree(const std::vector<T> &v) : n(v.size()), root(build(v)) {}

template<typename Data, typename Operation, template<typename> typename Allocator>
template<typename... Args>
void SegmentTree<Data, Operation, Allocator>::update(size_t left, size_t right, Args &&... args) {
    assert(left >= 0 && right < n);
    if (left > right) {
        return;
    }
    Operation op(std::forward<Args>(args)...);
    updateImpl(root, 0, n - 1, left, right, op);
}

template<typename Data, typename Operation, template<typename> typename Allocator>
Data SegmentTree<Data, Operation, Allocator>::query(size_t left, size_t right) {
    assert(left >= 0 && right < n);
    if (left > right) {
        return Data();
    }
    return queryImpl(root, 0, n - 1, left, right);
}

template<typename Data, typename Operation, template<typename> typename Allocator>
template<typename ...Args>
SegmentTree<Data, Operation, Allocator>::Node *SegmentTree<Data, Operation, Allocator>::makeNode(Args &&...args) {
    Node *ptr = alloc.allocate(1);
    std::construct_at(ptr, std::forward<Args>(args)...);
    return ptr;
}

template<typename Data, typename Operation, template<typename> typename Allocator>
template<typename T>
SegmentTree<Data, Operation, Allocator>::Node *SegmentTree<Data, Operation, Allocator>::build(const std::vector<T> &v) {
    return build(v, 0, v.size() - 1);
}

template<typename Data, typename Operation, template<typename> typename Allocator>
template<typename T>
SegmentTree<Data, Operation, Allocator>::Node *
SegmentTree<Data, Operation, Allocator>::build(const std::vector<T> &v, size_t left, size_t right) {
    if (left == right) {
        return makeNode(Data(v[left]));
    } else {
        size_t middle = getMiddle(left, right);
        auto leftSon = build(v, left, middle), rightSon = build(v, middle + 1, right);
        return makeNode(Data(leftSon->data, rightSon->data), leftSon, rightSon);
    }
}

template<typename Data, typename Operation, template<typename> typename Allocator>
size_t SegmentTree<Data, Operation, Allocator>::getMiddle(size_t left, size_t right) {
    return left + (right - left) / 2;
}

template<typename Data, typename Operation, template<typename> typename Allocator>
void SegmentTree<Data, Operation, Allocator>::push(SegmentTree::Node *node, size_t left, size_t right) {
    if (left != right) {
        if (!node->leftSon) { node->leftSon = makeNode(); }
        if (!node->rightSon) { node->rightSon = makeNode(); }
        auto middle = getMiddle(left, right);
        assert(apply(node->lazy, node->leftSon, left, middle));
        assert(apply(node->lazy, node->rightSon, middle + 1, right));
        node->lazy = Operation();
    }
}

template<typename Data, typename Operation, template<typename> typename Allocator>
void
SegmentTree<Data, Operation, Allocator>::updateImpl(SegmentTree::Node *node, size_t left, size_t right, size_t from,
                                                    size_t to, const Operation &op) {
    if (to < left || right < from) { return; }
    if (from <= left && right <= to && apply(op, node, left, right)) { return; }
    assert(left != right);
    push(node, left, right);
    auto middle = getMiddle(left, right);
    updateImpl(node->leftSon, left, middle, from, to, op);
    updateImpl(node->rightSon, middle + 1, right, from, to, op);
    node->data = Data(node->leftSon->data, node->rightSon->data);
}

template<typename Data, typename Operation, template<typename> typename Allocator>
bool SegmentTree<Data, Operation, Allocator>::apply(const Operation &op, SegmentTree::Node *node, size_t left,
                                                    size_t right) {
    node->lazy = Operation(node->lazy, op);
    return op.apply(node->data, left, right);
}

template<typename Data, typename Operation, template<typename> typename Allocator>
Data SegmentTree<Data, Operation, Allocator>::queryImpl(SegmentTree::Node *node, size_t left, size_t right, size_t from,
                                                        size_t to) {
    if (to < left || right < from) { return Data(); }
    if (from <= left && right <= to) { return node->data; }
    assert(left != right);
    push(node, left, right);
    auto middle = getMiddle(left, right);
    return Data(queryImpl(node->leftSon, left, middle, from, to),
                queryImpl(node->rightSon, middle + 1, right, from, to));
}




static constexpr size_t MAXN = 100000;

int main() {
    std::ifstream cin("arbint.in");
    std::ofstream cout("arbint.out");
    int n, q;
    cin >> n >> q;
    std::vector<int> v(n);
    cin >> v;
    SegmentTree<MaxData<int>, SetOperation<int>, StaticSize<4 * MAXN>::StaticAllocator> tree(v);
    for (int i = 0, type, a, b; i < q; i++) {
        cin >> type >> a >> b;
        if (type == 0) {
            cout << tree.query(a - 1, b - 1).max << "\n";
        } else {
            tree.update(a - 1, a - 1, b);
        }
    }
    return 0;
}