Advertisement
erek1e

IOI '05 P3 - Mountain

Jun 27th, 2023
536
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.63 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <cassert>
  5.  
  6. using namespace std;
  7.  
  8. vector<int> relevantID; // compressed indices
  9.  
  10. // Segment tree
  11. class Node {
  12. private:
  13.     long long mx = 0;
  14.     long long propAdd = 0; // for query that adds on range
  15.     long long propA = -1, propB = -1; // for query that sets range to A*i + B
  16.     Node * left, * right;
  17.     void add(long long k) { // adds k over this node's range
  18.         mx += k;
  19.         propAdd += k;
  20.     }
  21.     void set(int l, int r, long long a, long long b) { // sets this node's range to a*relevantID[i] + b
  22.         propAdd = 0;
  23.         propA = a, propB = b;
  24.         mx = max(a*relevantID[l] + b, a*relevantID[r-1] + b); // linear, so maximum is at one of the endpoints
  25.     }
  26.  
  27.     void prop(int l, int r) { // this node covers range [l, r)
  28.         if (!left) left = new Node();
  29.         if (!right) right = new Node();
  30.         if (propA == -1 && propB == -1) {
  31.             left->add(propAdd);
  32.             right->add(propAdd);
  33.         } else {
  34.             int m = (l + r) / 2;
  35.             propB += propAdd;
  36.             left->set(l, m, propA, propB);
  37.             right->set(m, r, propA, propB);
  38.         }
  39.         propAdd = 0;
  40.         propA = -1, propB = -1;
  41.     }
  42.  
  43. public:
  44.     // Updates
  45.     void rangeAdd(int l, int r, int ql, int qr, long long k) { // adds k between indices ql and qr
  46.         if (r <= ql || qr <= l) return;
  47.         if (ql <= l && r <= qr) add(k);
  48.         else {
  49.             prop(l, r);
  50.             int m = (l + r) / 2;
  51.             left->rangeAdd(l, m, ql, qr, k);
  52.             right->rangeAdd(m, r, ql, qr, k);
  53.             mx = max(left->mx, right->mx);
  54.         }
  55.     }
  56.     void rangeSet(int l, int r, int ql, int qr, long long a, long long b) { // sets range between ql and qr to a*relevantID[i] + b
  57.         if (r <= ql || qr <= l) return;
  58.         if (ql <= l && r <= qr) set(l, r, a, b);
  59.         else {
  60.             prop(l, r);
  61.             int m = (l + r) / 2;
  62.             left->rangeSet(l, m, ql, qr, a, b);
  63.             right->rangeSet(m, r, ql, qr, a, b);
  64.             mx = max(left->mx, right->mx);
  65.         }
  66.     }
  67.  
  68.     // Queries
  69.     long long getValue(int l, int r, int i) {
  70.         Node * node = this;
  71.         while (l+1 < r) {
  72.             node->prop(l, r);
  73.             int m = (l + r) / 2;
  74.             if (i < m) node = node->left, r = m;
  75.             else node = node->right, l = m;
  76.         }
  77.         return node->mx;
  78.     }
  79.     int firstGreaterThan(int l, int r, int h) {
  80.         if (mx <= h) return r; // no such nodes
  81.         Node * node = this;
  82.         while (l+1 < r) {
  83.             node->prop(l, r);
  84.             int m = (l + r) / 2;
  85.             if (node->left->mx > h) node = node->left, r = m;
  86.             else node = node->right, l = m;
  87.         }
  88.         return l;
  89.     }
  90. };
  91.  
  92. int main() {
  93.     // Input and compress indices of points
  94.     ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  95.     int n; cin >> n;
  96.     vector<int> queryA, queryB, queryD;
  97.     relevantID = {0, n};
  98.     for (char c; cin >> c && c != 'E'; ) {
  99.         if (c == 'I') {
  100.             int a, b, D; cin >> a >> b >> D;
  101.             queryA.push_back(a);
  102.             queryB.push_back(b);
  103.             queryD.push_back(D);
  104.             relevantID.push_back(a);
  105.             if (a > 1) relevantID.push_back(a-1);
  106.             relevantID.push_back(b);
  107.             if (b < n) relevantID.push_back(b+1);
  108.         } else {
  109.             int h; cin >> h;
  110.             queryA.push_back(-1);
  111.             queryB.push_back(-1);
  112.             queryD.push_back(h);
  113.         }
  114.     }
  115.     sort(relevantID.begin(), relevantID.end());
  116.     relevantID.resize(unique(relevantID.begin(), relevantID.end()) - relevantID.begin());
  117.     int m = relevantID.size();
  118.    
  119.     // Build segment tree of max height in range of size m on relevant indices
  120.     Node * root = new Node();
  121.     for (size_t q = 0; q < queryA.size(); ++q) {
  122.         if (queryA[q] == -1) { // Query
  123.             int h = queryD[q];
  124.             int pos = root->firstGreaterThan(0, m, h);
  125.  
  126.             int smallestIndex = n+1;
  127.             if (pos < m) {
  128.                 int curID = relevantID[pos], prvID = relevantID[pos-1];
  129.                 long long curV = root->getValue(0, m, pos), prvV = root->getValue(0, m, pos-1);
  130.                 // the function must be linear between prv and cur
  131.                 assert(prvV <= h);
  132.                 assert((curV-prvV)%(curID-prvID) == 0);
  133.                 int D = (curV-prvV)/(curID-prvID);
  134.                 int steps = (h-prvV)/D + 1;
  135.                 assert(prvID + steps <= curID);
  136.                
  137.                 smallestIndex = prvID + steps;
  138.             }
  139.            
  140.             cout << smallestIndex-1 << '\n';
  141.         } else { // Update
  142.             int a = queryA[q], b = queryB[q], D = queryD[q];
  143.             // find compressed positions
  144.             int first = lower_bound(relevantID.begin(), relevantID.end(), a) - relevantID.begin();
  145.             int last = lower_bound(relevantID.begin(), relevantID.end(), b) - relevantID.begin();
  146.  
  147.             long long lastInitial = root->getValue(0, m, last);
  148.  
  149.             // we know that first-1 is the compressed index for a-1 and last+1 is the compressed index for b+1, since we added a-1 and b+1 into relevantID
  150.             long long v = root->getValue(0, m, first-1);
  151.             // A*id + B = value, D * (a-1) + B = v <=> B = v - D(a-1)
  152.             root->rangeSet(0, m, first, last+1, D, v-D*(a-1LL));
  153.  
  154.             long long lastFinal = root->getValue(0, m, last);
  155.             long long suffixDelta = lastFinal - lastInitial;
  156.             root->rangeAdd(0, m, last+1, m, suffixDelta);
  157.         }
  158.     }
  159.     return 0;
  160. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement