Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -----------------------------------------------------------------------
- main.cpp
- -----------------------------------------------------------------------
- #include "parser.h"
- #include <iostream>
- using namespace std;
- void ParseAndProcessQuery(BudgetManager& manager, string_view line) {
- auto query = ParseQuery(line);
- if (!query) {
- return;
- }
- query->ProcessAndPrint(manager, cout);
- }
- int ReadNumberOnLine(istream& input) {
- std::string line;
- std::getline(input, line);
- return std::stoi(line);
- }
- int main() {
- BudgetManager manager;
- const int query_count = ReadNumberOnLine(cin);
- for (int i = 0; i < query_count; ++i) {
- std::string line;
- std::getline(cin, line);
- ParseAndProcessQuery(manager, line);
- }
- }
- -----------------------------------------------------------------------
- budget_manager.h
- -----------------------------------------------------------------------
- #pragma once
- #include "bulk_updater.h"
- #include "date.h"
- #include "entities.h"
- #include <vector>
- class BudgetManager {
- public:
- inline static const Date START_DATE{2000, 1, 1};
- inline static const Date END_DATE{2100, 1, 1};
- static size_t GetDayIndex(Date day) {return static_cast<size_t>(Date::ComputeDistance(START_DATE, day));}
- static IndexSegment MakeDateSegment(Date from, Date to) {return {GetDayIndex(from), GetDayIndex(to) + 1};}
- double ComputeSum(Date from, Date to) const {return tree_.ComputeSum(MakeDateSegment(from, to));}
- void AddBulkOperation(Date from, Date to, const BulkLinearUpdater& operation) {tree_.AddBulkOperation(MakeDateSegment(from, to), operation);}
- private:
- SummingSegmentTree<MoneyStruct, BulkLinearUpdater> tree_{GetDayIndex(END_DATE)};
- };
- -----------------------------------------------------------------------
- bulk_updater.h
- -----------------------------------------------------------------------
- #pragma once
- #include "entities.h"
- #include "summing_segment_tree.h"
- #include <cstdint>
- #include <cmath>
- struct BulkTaxApplier {
- double factor = 1.0;
- BulkTaxApplier(int _tax = 0) : factor(1.0 - double(_tax) / 100.0) {}
- };
- struct BulkMoneyAdder {
- MoneyStruct delta = {};
- };
- class BulkLinearUpdater {
- public:
- BulkLinearUpdater() = default;
- BulkLinearUpdater(const BulkMoneyAdder& add) : add_(add) {}
- BulkLinearUpdater(const BulkTaxApplier& tax) : tax_(tax) {}
- void CombineWith(const BulkLinearUpdater& other) {
- tax_.factor *= other.tax_.factor;
- add_.delta.earnings = add_.delta.earnings * other.tax_.factor + other.add_.delta.earnings;
- add_.delta.spendings += other.add_.delta.spendings;
- }
- MoneyStruct Collapse(const MoneyStruct& origin, IndexSegment segment) const {
- return MoneyStruct{origin.earnings * tax_.factor, origin.spendings}
- + add_.delta * double(segment.length());
- }
- private:
- BulkTaxApplier tax_;
- BulkMoneyAdder add_;
- };
- -----------------------------------------------------------------------
- date.h
- -----------------------------------------------------------------------
- #pragma once
- #include <regex>
- #include <string>
- #include <string_view>
- class Date {
- public:
- Date() {}
- Date(int year, int month, int day) : year_(year)
- , month_(month)
- , day_(day) {}
- static Date FromString(const std::string& str) {
- static const std::regex date_regex(R"/(([0-9]{4})-([0-9]{2})-([0-9]{2}))/");
- std::smatch m;
- if (!std::regex_match(str, m, date_regex)) {
- return {};
- }
- return Date(std::stoi(m[1].str()), std::stoi(m[2].str()), std::stoi(m[3].str()));
- }
- static Date FromString(std::string_view str) {return FromString(std::string(str));}
- static int ComputeDistance(Date from, Date to) {
- auto date_to_seconds = [](Date date) {
- tm timestamp;
- timestamp.tm_sec = 0;
- timestamp.tm_min = 0;
- timestamp.tm_hour = 0;
- timestamp.tm_mday = date.day_;
- timestamp.tm_mon = date.month_ - 1;
- timestamp.tm_year = date.year_ - 1900;
- timestamp.tm_isdst = 0;
- return mktime(×tamp);
- };
- static constexpr int SECONDS_IN_DAY = 60 * 60 * 24;
- return static_cast<int>((date_to_seconds(to) - date_to_seconds(from)) / SECONDS_IN_DAY);
- }
- private:
- int year_ = 0,
- month_ = 0,
- day_ = 0;
- };
- -----------------------------------------------------------------------
- entities.h
- -----------------------------------------------------------------------
- #pragma once
- struct MoneyStruct {
- double earnings;
- double spendings;
- MoneyStruct& operator+=(const MoneyStruct& other) {
- earnings += other.earnings;
- spendings += other.spendings;
- return *this;
- }
- MoneyStruct operator+(const MoneyStruct& other) const {
- return MoneyStruct(*this) += other;
- }
- MoneyStruct operator*(double factor) const {
- return {earnings * factor,
- spendings * factor};
- }
- operator double() const {
- return earnings - spendings;
- }
- };
- -----------------------------------------------------------------------
- parser.h
- -----------------------------------------------------------------------
- #pragma once
- #include "budget_manager.h"
- #include "date.h"
- #include <iostream>
- #include <memory>
- #include <optional>
- #include <regex>
- #include <unordered_map>
- struct ReadResult {
- void Print(std::ostream& out) {
- out << total_income << std::endl;
- }
- double total_income;
- };
- inline std::pair<std::string_view, std::optional<std::string_view>> SplitFirst(std::string_view input, char c) {
- auto cpos = input.find(c);
- if (cpos == input.npos) {
- return {input, {}};
- }
- return {input.substr(0, cpos), input.substr(cpos + 1)};
- }
- inline std::vector<std::string_view> Split(std::string_view input, char c) {
- std::vector<std::string_view> res;
- while (true) {
- auto [l, r] = SplitFirst(input, c);
- res.push_back(l);
- if (!r) {
- return res;
- }
- input = *r;
- }
- }
- class Query {
- public:
- virtual ~Query() = default;
- Query(Date from, Date to) : from_(from)
- , to_(to) {}
- Date GetFrom() const {return from_;}
- Date GetTo() const {return to_;}
- virtual void ProcessAndPrint(BudgetManager& budget, std::ostream& out) const = 0;
- private:
- Date from_, to_;
- };
- class ComputeQuery : public Query {
- public:
- using Query::Query;
- virtual ~ComputeQuery() = default;
- virtual ReadResult Process(const BudgetManager& budget) const = 0;
- void ProcessAndPrint(BudgetManager& budget, std::ostream& out) const override {
- Process(budget).Print(out);
- }
- };
- class ModifyQuery : public Query {
- public:
- using Query::Query;
- virtual ~ModifyQuery() = default;
- virtual void Process(BudgetManager& budget) const = 0;
- void ProcessAndPrint(BudgetManager& budget, std::ostream&) const override {
- Process(budget);
- }
- };
- class QueryFactory {
- public:
- virtual std::unique_ptr<Query> Construct(std::string_view config) const = 0;
- virtual ~QueryFactory() = default;
- static const QueryFactory& GetFactory(std::string_view id);
- };
- inline std::unique_ptr<Query> ParseQuery(std::string_view line) {
- auto [command, pconfig] = SplitFirst(line, ' ');
- const auto& factory = QueryFactory::GetFactory(command);
- return factory.Construct(pconfig.value_or(std::string_view{}));
- }
- inline std::vector<std::unique_ptr<Query>> ReadQueries(std::istream& input) {
- std::vector<std::unique_ptr<Query>> result;
- std::string line;
- std::getline(input, line);
- const int query_count = std::stoi(line);
- result.reserve(query_count);
- for (int i = 0; i < query_count; ++i) {
- std::getline(input, line);
- result.push_back(ParseQuery(line));
- }
- return result;
- }
- -----------------------------------------------------------------------
- parser.cpp
- -----------------------------------------------------------------------
- #include "parser.h"
- using namespace std;
- namespace queries {
- class ComputeIncome : public ComputeQuery {
- public:
- using ComputeQuery::ComputeQuery;
- ReadResult Process(const BudgetManager& budget) const override {
- return {budget.ComputeSum(GetFrom(), GetTo())};
- }
- class Factory : public QueryFactory {
- public:
- std::unique_ptr<Query> Construct(std::string_view config) const override {
- auto parts = Split(config, ' ');
- return std::make_unique<ComputeIncome>(Date::FromString(parts[0]), Date::FromString(parts[1]));
- }
- };
- };
- template <int HELPER>
- class Alter : public ModifyQuery {
- public:
- Alter(Date from, Date to, double amount)
- : ModifyQuery(from, to)
- , amount_(amount) {
- }
- void Process(BudgetManager& budget) const override {
- double day_income = amount_ / (Date::ComputeDistance(GetFrom(), GetTo()) + 1);
- MoneyStruct daily_change;
- if (HELPER == 1) {
- daily_change = MoneyStruct{day_income, {}};
- } else {
- daily_change = MoneyStruct{{}, day_income};
- }
- budget.AddBulkOperation(GetFrom(), GetTo(), BulkMoneyAdder{daily_change});
- }
- class Factory : public QueryFactory {
- public:
- std::unique_ptr<Query> Construct(std::string_view config) const override {
- auto parts = Split(config, ' ');
- double payload = std::stod(std::string(parts[2]));
- if (HELPER == 1) {
- return std::make_unique<Alter<1>>(Date::FromString(parts[0]), Date::FromString(parts[1]), payload);
- } else {
- return std::make_unique<Alter<-1>>(Date::FromString(parts[0]), Date::FromString(parts[1]), payload);
- }
- }
- };
- private:
- double amount_;
- };
- class PayTax : public ModifyQuery {
- public:
- PayTax(Date from, Date to, double amount)
- : ModifyQuery(from, to)
- , amount_(amount) {
- }
- void Process(BudgetManager& budget) const override {
- budget.AddBulkOperation(GetFrom(), GetTo(), BulkTaxApplier{amount_});
- }
- class Factory : public QueryFactory {
- public:
- std::unique_ptr<Query> Construct(std::string_view config) const override {
- auto parts = Split(config, ' ');
- double payload = std::stod(std::string(parts[2]));
- return std::make_unique<PayTax>(Date::FromString(parts[0]), Date::FromString(parts[1]), payload);
- }
- };
- private:
- int amount_ = 0;
- };
- }//end namespace queries
- const QueryFactory& QueryFactory::GetFactory(std::string_view id) {
- static queries::ComputeIncome::Factory compute_income;
- static queries::Alter<1>::Factory earn;
- static queries::Alter<-1>::Factory spend;
- static queries::PayTax::Factory pay_tax;
- static std::unordered_map<std::string_view, const QueryFactory&> factories
- = {{"ComputeIncome"sv, compute_income}, {"Earn"sv, earn}, {"Spend"sv, spend}, {"PayTax"sv, pay_tax}};
- return factories.at(id);
- }
- -----------------------------------------------------------------------
- summing_segment_tree.h
- -----------------------------------------------------------------------
- #pragma once
- #include <memory>
- #include <utility>
- struct IndexSegment {
- public:
- size_t length() const {return right - left;}
- bool empty() const {return length() == 0;}
- bool Contains(IndexSegment other) const {
- return left <= other.left && other.right <= right;
- }
- static bool AreIntersected(IndexSegment lhs, IndexSegment rhs) {
- return !(lhs.right <= rhs.left || rhs.right <= lhs.left);
- }
- size_t left;
- size_t right;
- };
- template <typename Data, typename BulkOperation>
- class SummingSegmentTree {
- public:
- SummingSegmentTree(size_t size) : root_(Build({0, size})) {}
- Data ComputeSum(IndexSegment segment) const {
- return this->TraverseWithQuery(root_, segment, ComputeSumVisitor{});
- }
- void AddBulkOperation(IndexSegment segment, const BulkOperation& operation) {
- this->TraverseWithQuery(root_, segment, AddBulkOperationVisitor{operation});
- }
- private:
- struct Node;
- using NodeHolder = std::unique_ptr<Node>;
- struct Node {
- NodeHolder left;
- NodeHolder right;
- IndexSegment segment;
- Data data;
- BulkOperation postponed_bulk_operation;
- };
- static NodeHolder Build(IndexSegment segment) {
- if (segment.empty()) {
- return nullptr;
- } else if (segment.length() == 1) {
- return std::make_unique<Node>(Node{{}, {}, segment, {}, {}});
- } else {
- const size_t middle = segment.left + segment.length() / 2;
- return std::make_unique<Node>(
- Node{Build({segment.left, middle}), Build({middle, segment.right}), segment, {}, {}});
- }
- }
- template <typename Visitor>
- static typename Visitor::ResultType TraverseWithQuery(const NodeHolder& node, IndexSegment query_segment,
- Visitor visitor) {
- if (!node || !IndexSegment::AreIntersected(node->segment, query_segment)) {
- return visitor.ProcessEmpty(node);
- } else {
- PropagateBulkOperation(node);
- if (query_segment.Contains(node->segment)) {
- return visitor.ProcessFull(node);
- } else {
- if constexpr (std::is_void_v<typename Visitor::ResultType>) {
- TraverseWithQuery(node->left, query_segment, visitor);
- TraverseWithQuery(node->right, query_segment, visitor);
- return visitor.ProcessPartial(node, query_segment);
- } else {
- return visitor.ProcessPartial(node, query_segment,
- TraverseWithQuery(node->left, query_segment, visitor),
- TraverseWithQuery(node->right, query_segment, visitor));
- }
- }
- }
- }
- class ComputeSumVisitor {
- public:
- using ResultType = Data;
- Data ProcessEmpty(const NodeHolder&) const {
- return {};
- }
- Data ProcessFull(const NodeHolder& node) const {
- return node->data;
- }
- Data ProcessPartial(const NodeHolder&, IndexSegment, const Data& left_result, const Data& right_result) const {
- return left_result + right_result;
- }
- };
- class AddBulkOperationVisitor {
- public:
- using ResultType = void;
- explicit AddBulkOperationVisitor(const BulkOperation& operation)
- : operation_(operation) {
- }
- void ProcessEmpty(const NodeHolder&) const {}
- void ProcessFull(const NodeHolder& node) const {
- node->postponed_bulk_operation.CombineWith(operation_);
- node->data = operation_.Collapse(node->data, node->segment);
- }
- void ProcessPartial(const NodeHolder& node, IndexSegment) const {
- node->data = (node->left ? node->left->data : Data()) + (node->right ? node->right->data : Data());
- }
- private:
- const BulkOperation& operation_;
- };
- static void PropagateBulkOperation(const NodeHolder& node) {
- for (auto* child_ptr : {node->left.get(), node->right.get()}) {
- if (child_ptr) {
- child_ptr->postponed_bulk_operation.CombineWith(node->postponed_bulk_operation);
- child_ptr->data = node->postponed_bulk_operation.Collapse(child_ptr->data, child_ptr->segment);
- }
- }
- node->postponed_bulk_operation = BulkOperation();
- }
- private:
- NodeHolder root_;
- };
Advertisement
Add Comment
Please, Sign In to add comment