shushus

Спринт 13. Возврат оптом - получаем много объектов.

Apr 20th, 2023
849
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.06 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. main.cpp
  3. -----------------------------------------------------------------------
  4. #include "parser.h"
  5.  
  6. #include <iostream>
  7.  
  8. using namespace std;
  9.  
  10. void ParseAndProcessQuery(BudgetManager& manager, string_view line) {
  11.     auto query = ParseQuery(line);
  12.  
  13.     if (!query) {
  14.         return;
  15.     }
  16.  
  17.     query->ProcessAndPrint(manager, cout);
  18. }
  19.  
  20. int ReadNumberOnLine(istream& input) {
  21.     std::string line;
  22.     std::getline(input, line);
  23.     return std::stoi(line);
  24. }
  25.  
  26. int main() {
  27.     BudgetManager manager;
  28.  
  29.     const int query_count = ReadNumberOnLine(cin);
  30.  
  31.     for (int i = 0; i < query_count; ++i) {
  32.         std::string line;
  33.         std::getline(cin, line);
  34.         ParseAndProcessQuery(manager, line);
  35.     }
  36. }
  37. -----------------------------------------------------------------------
  38. budget_manager.h
  39. -----------------------------------------------------------------------
  40. #pragma once
  41.  
  42. #include "bulk_updater.h"
  43. #include "date.h"
  44. #include "entities.h"
  45.  
  46. #include <vector>
  47.  
  48. class BudgetManager {
  49. public:
  50.     inline static const Date START_DATE{2000, 1, 1};
  51.     inline static const Date END_DATE{2100, 1, 1};
  52.  
  53.     static size_t GetDayIndex(Date day) {return static_cast<size_t>(Date::ComputeDistance(START_DATE, day));}
  54.     static IndexSegment MakeDateSegment(Date from, Date to) {return {GetDayIndex(from), GetDayIndex(to) + 1};}
  55.     double ComputeSum(Date from, Date to) const {return tree_.ComputeSum(MakeDateSegment(from, to));}
  56.     void AddBulkOperation(Date from, Date to, const BulkLinearUpdater& operation) {tree_.AddBulkOperation(MakeDateSegment(from, to), operation);}
  57.  
  58. private:
  59.     SummingSegmentTree<MoneyStruct, BulkLinearUpdater> tree_{GetDayIndex(END_DATE)};
  60. };
  61. -----------------------------------------------------------------------
  62. bulk_updater.h
  63. -----------------------------------------------------------------------
  64. #pragma once
  65.  
  66. #include "entities.h"
  67. #include "summing_segment_tree.h"
  68.  
  69. #include <cstdint>
  70. #include <cmath>
  71.  
  72. struct BulkTaxApplier {
  73.     double factor = 1.0;
  74.     BulkTaxApplier(int _tax = 0) : factor(1.0 - double(_tax) / 100.0) {}
  75. };
  76.  
  77. struct BulkMoneyAdder {
  78.     MoneyStruct delta = {};
  79. };
  80.  
  81. class BulkLinearUpdater {
  82. public:
  83.     BulkLinearUpdater() = default;
  84.     BulkLinearUpdater(const BulkMoneyAdder& add) : add_(add) {}
  85.     BulkLinearUpdater(const BulkTaxApplier& tax) : tax_(tax) {}
  86.  
  87.     void CombineWith(const BulkLinearUpdater& other) {
  88.         tax_.factor *= other.tax_.factor;
  89.         add_.delta.earnings = add_.delta.earnings * other.tax_.factor + other.add_.delta.earnings;
  90.         add_.delta.spendings += other.add_.delta.spendings;
  91.     }
  92.  
  93.     MoneyStruct Collapse(const MoneyStruct& origin, IndexSegment segment) const {
  94.         return MoneyStruct{origin.earnings * tax_.factor, origin.spendings}
  95.                + add_.delta * double(segment.length());
  96.     }
  97.  
  98. private:
  99.     BulkTaxApplier tax_;
  100.     BulkMoneyAdder add_;
  101. };
  102. -----------------------------------------------------------------------
  103. date.h
  104. -----------------------------------------------------------------------
  105. #pragma once
  106.  
  107. #include <regex>
  108. #include <string>
  109. #include <string_view>
  110.  
  111. class Date {
  112. public:
  113.     Date() {}
  114.    
  115.     Date(int year, int month, int day) : year_(year)
  116.                                        , month_(month)
  117.                                        , day_(day) {}
  118.  
  119.     static Date FromString(const std::string& str) {
  120.         static const std::regex date_regex(R"/(([0-9]{4})-([0-9]{2})-([0-9]{2}))/");
  121.         std::smatch m;
  122.  
  123.         if (!std::regex_match(str, m, date_regex)) {
  124.             return {};
  125.         }
  126.  
  127.         return Date(std::stoi(m[1].str()), std::stoi(m[2].str()), std::stoi(m[3].str()));
  128.     }
  129.  
  130.     static Date FromString(std::string_view str) {return FromString(std::string(str));}
  131.  
  132.     static int ComputeDistance(Date from, Date to) {
  133.         auto date_to_seconds = [](Date date) {
  134.             tm timestamp;
  135.             timestamp.tm_sec = 0;
  136.             timestamp.tm_min = 0;
  137.             timestamp.tm_hour = 0;
  138.             timestamp.tm_mday = date.day_;
  139.             timestamp.tm_mon = date.month_ - 1;
  140.             timestamp.tm_year = date.year_ - 1900;
  141.             timestamp.tm_isdst = 0;
  142.             return mktime(&timestamp);
  143.         };
  144.  
  145.         static constexpr int SECONDS_IN_DAY = 60 * 60 * 24;
  146.         return static_cast<int>((date_to_seconds(to) - date_to_seconds(from)) / SECONDS_IN_DAY);
  147.     }
  148.  
  149. private:
  150.     int year_ = 0,
  151.     month_ = 0,
  152.     day_ = 0;
  153. };
  154. -----------------------------------------------------------------------
  155. entities.h
  156. -----------------------------------------------------------------------
  157. #pragma once
  158.  
  159. struct MoneyStruct {
  160.     double earnings;
  161.     double spendings;
  162.  
  163.     MoneyStruct& operator+=(const MoneyStruct& other) {
  164.         earnings += other.earnings;
  165.         spendings += other.spendings;
  166.        
  167.         return *this;
  168.     }
  169.    
  170.     MoneyStruct operator+(const MoneyStruct& other) const {
  171.         return MoneyStruct(*this) += other;
  172.     }
  173.    
  174.     MoneyStruct operator*(double factor) const {
  175.         return {earnings * factor,
  176.                 spendings * factor};
  177.     }
  178.    
  179.     operator double() const {
  180.         return earnings - spendings;
  181.     }
  182. };
  183. -----------------------------------------------------------------------
  184. parser.h
  185. -----------------------------------------------------------------------
  186. #pragma once
  187. #include "budget_manager.h"
  188. #include "date.h"
  189.  
  190. #include <iostream>
  191. #include <memory>
  192. #include <optional>
  193. #include <regex>
  194. #include <unordered_map>
  195.  
  196. struct ReadResult {
  197.     void Print(std::ostream& out) {
  198.         out << total_income << std::endl;
  199.     }
  200.  
  201.     double total_income;
  202. };
  203.  
  204. inline std::pair<std::string_view, std::optional<std::string_view>> SplitFirst(std::string_view input, char c) {
  205.     auto cpos = input.find(c);
  206.     if (cpos == input.npos) {
  207.         return {input, {}};
  208.     }
  209.  
  210.     return {input.substr(0, cpos), input.substr(cpos + 1)};
  211. }
  212.  
  213. inline std::vector<std::string_view> Split(std::string_view input, char c) {
  214.     std::vector<std::string_view> res;
  215.     while (true) {
  216.         auto [l, r] = SplitFirst(input, c);
  217.         res.push_back(l);
  218.         if (!r) {
  219.             return res;
  220.         }
  221.         input = *r;
  222.     }
  223. }
  224.  
  225. class Query {
  226. public:
  227.     virtual ~Query() = default;
  228.  
  229.     Query(Date from, Date to) : from_(from)
  230.                               , to_(to) {}
  231.  
  232.     Date GetFrom() const {return from_;}
  233.     Date GetTo() const {return to_;}
  234.  
  235.     virtual void ProcessAndPrint(BudgetManager& budget, std::ostream& out) const = 0;
  236.  
  237. private:
  238.     Date from_, to_;
  239. };
  240.  
  241. class ComputeQuery : public Query {
  242. public:
  243.     using Query::Query;
  244.     virtual ~ComputeQuery() = default;
  245.     virtual ReadResult Process(const BudgetManager& budget) const = 0;
  246.  
  247.     void ProcessAndPrint(BudgetManager& budget, std::ostream& out) const override {
  248.         Process(budget).Print(out);
  249.     }
  250. };
  251.  
  252. class ModifyQuery : public Query {
  253. public:
  254.     using Query::Query;
  255.     virtual ~ModifyQuery() = default;
  256.     virtual void Process(BudgetManager& budget) const = 0;
  257.  
  258.     void ProcessAndPrint(BudgetManager& budget, std::ostream&) const override {
  259.         Process(budget);
  260.     }
  261. };
  262.  
  263. class QueryFactory {
  264. public:
  265.     virtual std::unique_ptr<Query> Construct(std::string_view config) const = 0;
  266.     virtual ~QueryFactory() = default;
  267.  
  268.     static const QueryFactory& GetFactory(std::string_view id);
  269. };
  270.  
  271. inline std::unique_ptr<Query> ParseQuery(std::string_view line) {
  272.     auto [command, pconfig] = SplitFirst(line, ' ');
  273.  
  274.     const auto& factory = QueryFactory::GetFactory(command);
  275.     return factory.Construct(pconfig.value_or(std::string_view{}));
  276. }
  277.  
  278. inline std::vector<std::unique_ptr<Query>> ReadQueries(std::istream& input) {
  279.     std::vector<std::unique_ptr<Query>> result;
  280.     std::string line;
  281.     std::getline(input, line);
  282.     const int query_count = std::stoi(line);
  283.     result.reserve(query_count);
  284.  
  285.     for (int i = 0; i < query_count; ++i) {
  286.         std::getline(input, line);
  287.         result.push_back(ParseQuery(line));
  288.     }
  289.  
  290.     return result;
  291. }
  292. -----------------------------------------------------------------------
  293. parser.cpp
  294. -----------------------------------------------------------------------
  295. #include "parser.h"
  296.  
  297. using namespace std;
  298.  
  299. namespace queries {
  300. class ComputeIncome : public ComputeQuery {
  301. public:
  302.     using ComputeQuery::ComputeQuery;
  303.     ReadResult Process(const BudgetManager& budget) const override {
  304.         return {budget.ComputeSum(GetFrom(), GetTo())};
  305.     }
  306.  
  307.     class Factory : public QueryFactory {
  308.     public:
  309.         std::unique_ptr<Query> Construct(std::string_view config) const override {
  310.             auto parts = Split(config, ' ');
  311.             return std::make_unique<ComputeIncome>(Date::FromString(parts[0]), Date::FromString(parts[1]));
  312.         }
  313.     };
  314. };
  315.  
  316. template <int HELPER>
  317. class Alter : public ModifyQuery {
  318. public:
  319.  
  320.     Alter(Date from, Date to, double amount)
  321.         : ModifyQuery(from, to)
  322.         , amount_(amount) {
  323.     }
  324.  
  325.     void Process(BudgetManager& budget) const override {
  326.         double day_income = amount_ / (Date::ComputeDistance(GetFrom(), GetTo()) + 1);
  327.         MoneyStruct daily_change;
  328.        
  329.         if (HELPER == 1) {
  330.             daily_change = MoneyStruct{day_income, {}};
  331.         } else {
  332.             daily_change = MoneyStruct{{}, day_income};
  333.         }
  334.        
  335.         budget.AddBulkOperation(GetFrom(), GetTo(), BulkMoneyAdder{daily_change});
  336.     }
  337.  
  338.     class Factory : public QueryFactory {
  339.     public:
  340.         std::unique_ptr<Query> Construct(std::string_view config) const override {
  341.             auto parts = Split(config, ' ');
  342.             double payload = std::stod(std::string(parts[2]));
  343.             if (HELPER == 1) {
  344.                 return std::make_unique<Alter<1>>(Date::FromString(parts[0]), Date::FromString(parts[1]), payload);
  345.             } else {
  346.                 return std::make_unique<Alter<-1>>(Date::FromString(parts[0]), Date::FromString(parts[1]), payload);
  347.             }
  348.         }
  349.     };
  350.  
  351. private:
  352.     double amount_;
  353. };
  354.  
  355. class PayTax : public ModifyQuery {
  356. public:    
  357.     PayTax(Date from, Date to, double amount)
  358.         : ModifyQuery(from, to)
  359.         , amount_(amount) {
  360.     }
  361.  
  362.     void Process(BudgetManager& budget) const override {
  363.         budget.AddBulkOperation(GetFrom(), GetTo(), BulkTaxApplier{amount_});
  364.     }
  365.  
  366.     class Factory : public QueryFactory {
  367.     public:
  368.         std::unique_ptr<Query> Construct(std::string_view config) const override {
  369.             auto parts = Split(config, ' ');
  370.             double payload = std::stod(std::string(parts[2]));
  371.             return std::make_unique<PayTax>(Date::FromString(parts[0]), Date::FromString(parts[1]), payload);
  372.         }
  373.     };
  374.  
  375. private:
  376.     int amount_ = 0;
  377. };
  378.  
  379. }//end namespace queries
  380.  
  381. const QueryFactory& QueryFactory::GetFactory(std::string_view id) {
  382.     static queries::ComputeIncome::Factory compute_income;
  383.     static queries::Alter<1>::Factory earn;
  384.     static queries::Alter<-1>::Factory spend;
  385.     static queries::PayTax::Factory pay_tax;
  386.     static std::unordered_map<std::string_view, const QueryFactory&> factories
  387.         = {{"ComputeIncome"sv, compute_income}, {"Earn"sv, earn},  {"Spend"sv, spend}, {"PayTax"sv, pay_tax}};
  388.  
  389.     return factories.at(id);
  390. }
  391. -----------------------------------------------------------------------
  392. summing_segment_tree.h
  393. -----------------------------------------------------------------------
  394. #pragma once
  395. #include <memory>
  396. #include <utility>
  397.  
  398. struct IndexSegment {
  399. public:
  400.     size_t length() const {return right - left;}
  401.     bool empty() const {return length() == 0;}
  402.  
  403.     bool Contains(IndexSegment other) const {
  404.         return left <= other.left && other.right <= right;
  405.     }
  406.  
  407.     static bool AreIntersected(IndexSegment lhs, IndexSegment rhs) {
  408.         return !(lhs.right <= rhs.left || rhs.right <= lhs.left);
  409.     }
  410.  
  411.     size_t left;
  412.     size_t right;
  413. };
  414.  
  415. template <typename Data, typename BulkOperation>
  416. class SummingSegmentTree {
  417. public:
  418.     SummingSegmentTree(size_t size) : root_(Build({0, size})) {}
  419.  
  420.     Data ComputeSum(IndexSegment segment) const {
  421.         return this->TraverseWithQuery(root_, segment, ComputeSumVisitor{});
  422.     }
  423.  
  424.     void AddBulkOperation(IndexSegment segment, const BulkOperation& operation) {
  425.         this->TraverseWithQuery(root_, segment, AddBulkOperationVisitor{operation});
  426.     }
  427.  
  428. private:
  429.     struct Node;
  430.     using NodeHolder = std::unique_ptr<Node>;
  431.  
  432.     struct Node {
  433.         NodeHolder left;
  434.         NodeHolder right;
  435.         IndexSegment segment;
  436.         Data data;
  437.         BulkOperation postponed_bulk_operation;
  438.     };
  439.  
  440.     static NodeHolder Build(IndexSegment segment) {
  441.         if (segment.empty()) {
  442.             return nullptr;
  443.         } else if (segment.length() == 1) {
  444.             return std::make_unique<Node>(Node{{}, {}, segment, {}, {}});
  445.         } else {
  446.             const size_t middle = segment.left + segment.length() / 2;
  447.             return std::make_unique<Node>(
  448.                 Node{Build({segment.left, middle}), Build({middle, segment.right}), segment, {}, {}});
  449.         }
  450.     }
  451.  
  452.     template <typename Visitor>
  453.     static typename Visitor::ResultType TraverseWithQuery(const NodeHolder& node, IndexSegment query_segment,
  454.                                                           Visitor visitor) {
  455.         if (!node || !IndexSegment::AreIntersected(node->segment, query_segment)) {
  456.             return visitor.ProcessEmpty(node);
  457.         } else {
  458.             PropagateBulkOperation(node);
  459.             if (query_segment.Contains(node->segment)) {
  460.                 return visitor.ProcessFull(node);
  461.             } else {
  462.                 if constexpr (std::is_void_v<typename Visitor::ResultType>) {
  463.                     TraverseWithQuery(node->left, query_segment, visitor);
  464.                     TraverseWithQuery(node->right, query_segment, visitor);
  465.                     return visitor.ProcessPartial(node, query_segment);
  466.                 } else {
  467.                     return visitor.ProcessPartial(node, query_segment,
  468.                                                   TraverseWithQuery(node->left, query_segment, visitor),
  469.                                                   TraverseWithQuery(node->right, query_segment, visitor));
  470.                 }
  471.             }
  472.         }
  473.     }
  474.  
  475.     class ComputeSumVisitor {
  476.     public:
  477.         using ResultType = Data;
  478.  
  479.         Data ProcessEmpty(const NodeHolder&) const {
  480.             return {};
  481.         }
  482.  
  483.         Data ProcessFull(const NodeHolder& node) const {
  484.             return node->data;
  485.         }
  486.  
  487.         Data ProcessPartial(const NodeHolder&, IndexSegment, const Data& left_result, const Data& right_result) const {
  488.             return left_result + right_result;
  489.         }
  490.     };
  491.  
  492.     class AddBulkOperationVisitor {
  493.     public:
  494.         using ResultType = void;
  495.  
  496.         explicit AddBulkOperationVisitor(const BulkOperation& operation)
  497.             : operation_(operation) {
  498.         }
  499.  
  500.         void ProcessEmpty(const NodeHolder&) const {}
  501.  
  502.         void ProcessFull(const NodeHolder& node) const {
  503.             node->postponed_bulk_operation.CombineWith(operation_);
  504.             node->data = operation_.Collapse(node->data, node->segment);
  505.         }
  506.  
  507.         void ProcessPartial(const NodeHolder& node, IndexSegment) const {
  508.             node->data = (node->left ? node->left->data : Data()) + (node->right ? node->right->data : Data());
  509.         }
  510.  
  511.     private:
  512.         const BulkOperation& operation_;
  513.     };
  514.  
  515.     static void PropagateBulkOperation(const NodeHolder& node) {
  516.         for (auto* child_ptr : {node->left.get(), node->right.get()}) {
  517.             if (child_ptr) {
  518.                 child_ptr->postponed_bulk_operation.CombineWith(node->postponed_bulk_operation);
  519.                 child_ptr->data = node->postponed_bulk_operation.Collapse(child_ptr->data, child_ptr->segment);
  520.             }
  521.         }
  522.         node->postponed_bulk_operation = BulkOperation();
  523.     }
  524.  
  525. private:
  526.     NodeHolder root_;
  527. };
Advertisement
Add Comment
Please, Sign In to add comment