Advertisement
erek1e

IOI '19 - Rectangles

Jul 23rd, 2023
832
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.26 KB | None | 0 0
  1. #include "rect.h"
  2. #include <iostream>
  3. #include <stack>
  4. #include <tuple>
  5.  
  6. using namespace std;
  7.  
  8. enum direction { Left, Right, Up, Down };
  9. int dr[]{0, 0, -1, +1}, dc[]{-1, +1, 0, 0};
  10.  
  11. const int N = 2500, LG = 12;
  12. int maxP2[1+N]{};
  13.  
  14. long long count_rectangles(vector<vector<int>> a) {
  15.     int n = a.size(), m = a[0].size();
  16.  
  17.     vector<vector<int>> reach[4]; // distance to closest in each direction that is greater than or equal to
  18.     for (int d = 0; d < 4; ++d) reach[d].assign(n, vector<int>(m));
  19.     for (int i = 0; i < n; ++i) { // row
  20.         { // left
  21.             stack<int> candidates;
  22.             for (int j = 0; j < m; ++j) {
  23.                 while (!candidates.empty() && a[i][candidates.top()] < a[i][j]) candidates.pop();
  24.                 reach[0][i][j] = candidates.empty() ? -1 : candidates.top();
  25.                 reach[0][i][j] = j - reach[0][i][j];
  26.                 candidates.push(j);
  27.             }
  28.         }
  29.         { // right
  30.             stack<int> candidates;
  31.             for (int j = m-1; j >= 0; --j) {
  32.                 while (!candidates.empty() && a[i][candidates.top()] < a[i][j]) candidates.pop();
  33.                 reach[1][i][j] = candidates.empty() ? m : candidates.top();
  34.                 reach[1][i][j] = reach[1][i][j] - j;
  35.                 candidates.push(j);
  36.             }
  37.         }
  38.     }
  39.     for (int j = 0; j < m; ++j) { // column
  40.         { // up
  41.             stack<int> candidates;
  42.             for (int i = 0; i < n; ++i) {
  43.                 while (!candidates.empty() && a[candidates.top()][j] < a[i][j]) candidates.pop();
  44.                 reach[2][i][j] = candidates.empty() ? -1 : candidates.top();
  45.                 reach[2][i][j] = i - reach[2][i][j];
  46.                 candidates.push(i);
  47.             }
  48.         }
  49.         { // down
  50.             stack<int> candidates;
  51.             for (int i = n-1; i >= 0; --i) {
  52.                 while (!candidates.empty() && a[candidates.top()][j] < a[i][j]) candidates.pop();
  53.                 reach[3][i][j] = candidates.empty() ? n : candidates.top();
  54.                 reach[3][i][j] = reach[3][i][j] - i;
  55.                 candidates.push(i);
  56.             }
  57.         }
  58.     }
  59.    
  60.     /* The letters below represent values just outside the border of the rectangle, adjacent to corners of the rectangle
  61.          a     e
  62.         .-------.
  63.        c|       |d
  64.         |       |
  65.         |       |
  66.         .-------.
  67.          b     f
  68.     */
  69.    
  70.     vector<tuple<int, int, int, int>> rectangles;
  71.     auto consider = [&](int i, int j, int h, int w) { // rectangle with given top left position, width, height
  72.         if (i <= 0 || j <= 0 || i+h-1 >= n-1 || j+w-1 >= m-1) return;
  73.         if ( w < 1 || h < 1) return;
  74.         // check that all sides can reach one another
  75.         // if (RMQ(Right, j-1, i, i+h-1) <= w) return;
  76.         // if (RMQ(Left, j+w, i, i+h-1) <= w) return;
  77.         // if (RMQ(Down, i-1, j, j+w-1) <= h) return;
  78.         // if (RMQ(Up, i+h, j, j+w-1) <= h) return;
  79.         // ++rectangles;
  80.         rectangles.emplace_back(i, j, h, w);
  81.     };
  82.     for (int i = 1; i < n-1; ++i) {
  83.         for (int j = 1; j < m-1; ++j) {
  84.             { // Case 1: a <= b && c <= d: consider i, j as top left
  85.                 int height = reach[Down][i-1][j] - 1, width = reach[Right][i][j-1] - 1;
  86.                 consider(i, j, height, width);
  87.             }
  88.  
  89.             { // Case 2: a <= b && c > d: consider i, j as top right
  90.                 int width = reach[Left][i][j+1] - 1;
  91.                 int jLeft = j-width+1;
  92.                 if (jLeft > 0 && a[i][jLeft-1] > a[i][j+1]) { // c > d, not equal
  93.                     int height = reach[Down][i-1][jLeft] - 1;
  94.                     consider(i, jLeft, height, width);
  95.                 }
  96.             }
  97.  
  98.             { // Case 3: a > b && c <= d: consider i, j as bottom left
  99.                 int height = reach[Up][i+1][j] - 1;
  100.                 int iTop = i-height+1;
  101.                 if (iTop > 0 && a[iTop-1][j] > a[i+1][j]) { // a > b, not equal
  102.                     int width = reach[Right][iTop][j-1] - 1;
  103.                     consider(iTop, j, height, width);
  104.                 }
  105.             }
  106.  
  107.             { // Case 4: a > b && c > d && e <= f: consider i, j, as top right
  108.                 int height = reach[Down][i-1][j] - 1, width = reach[Left][i][j+1] - 1;
  109.                 int iBottom = i+height-1, jLeft = j-width+1;
  110.                 if (iBottom+1 < n && jLeft > 0) {
  111.                     // check that a > b and c > d
  112.                     if (a[i-1][jLeft] > a[iBottom+1][jLeft] && a[i][jLeft-1] > a[i][j+1]) {
  113.                         consider(i, jLeft, height, width);
  114.                     }
  115.                 }
  116.             }
  117.  
  118.             { // Case 5: a > b && c > d && e > f: consider i, j as bottom right
  119.                 int height = reach[Up][i+1][j] - 1;
  120.                 int iTop = i-height+1;
  121.                 if (iTop > 0 && a[iTop-1][j] > a[i+1][j]) { // e > f, not equal
  122.                     int width = reach[Left][iTop][j+1] - 1;
  123.                     int jLeft = j-width+1;
  124.                     // check that a > b and c > d
  125.                     if (a[iTop-1][jLeft] > a[i+1][jLeft] && a[iTop][jLeft-1] > a[iTop][j+1]) {
  126.                         consider(iTop, jLeft, height, width);
  127.                     }
  128.                 }
  129.             }
  130.         }
  131.     }
  132.    
  133.     // test reach in all four directions separately to reduce memory usage by a factor of 4
  134.    
  135.     // maxP2
  136.     for (int i = 2; i <= max(n, m); ++i) maxP2[i] = maxP2[i-1] + !(i & (i-1));
  137.  
  138.     vector<vector<int>> reachRMQ[1+LG];
  139.     for (int k = 0; k <= LG; ++k) reachRMQ[k].assign(n, vector<int>(m));
  140.     auto RMQ = [&](int dir, int rc, int l, int r) {
  141.         int p2 = maxP2[r-l+1];
  142.         if (dir == 0 || dir == 1) {
  143.             int j = rc;
  144.             return min(reachRMQ[p2][l][j], reachRMQ[p2][r-(1<<p2)+1][j]);
  145.         } else {
  146.             int i = rc;
  147.             return min(reachRMQ[p2][i][l], reachRMQ[p2][i][r-(1<<p2)+1]);
  148.         }
  149.     };
  150.  
  151.     vector<tuple<int, int, int, int>> rectangles2;
  152.  
  153.     // Left
  154.     for (int j = 0; j < m; ++j) { // column
  155.         for (int i = 0; i < n; ++i) reachRMQ[0][i][j] = reach[0][i][j];
  156.         for (int k = 1; k <= LG; ++k) {
  157.             for (int i = 0; i < n; ++i) {
  158.                 int i2 = i + (1 << (k-1));
  159.                 if (i2 >= n) {
  160.                     reachRMQ[k][i][j] = reachRMQ[k-1][i][j];
  161.                 } else {
  162.                     reachRMQ[k][i][j] = min(reachRMQ[k-1][i][j], reachRMQ[k-1][i + (1 << (k-1))][j]);
  163.                 }
  164.             }
  165.         }
  166.     }
  167.     rectangles2.clear();
  168.     for (auto [i, j, h, w] : rectangles) {
  169.         if (RMQ(Left, j+w, i, i+h-1) > w) rectangles2.emplace_back(i, j, h, w);
  170.     }
  171.     rectangles = rectangles2;
  172.  
  173.     // Right
  174.     for (int k = 0; k <= LG; ++k) reachRMQ[k].assign(n, vector<int>(m));
  175.     for (int j = 0; j < m; ++j) { // column
  176.         for (int i = 0; i < n; ++i) reachRMQ[0][i][j] = reach[1][i][j];
  177.         for (int k = 1; k <= LG; ++k) {
  178.             for (int i = 0; i < n; ++i) {
  179.                 int i2 = i + (1 << (k-1));
  180.                 if (i2 >= n) {
  181.                     reachRMQ[k][i][j] = reachRMQ[k-1][i][j];
  182.                 } else {
  183.                     reachRMQ[k][i][j] = min(reachRMQ[k-1][i][j], reachRMQ[k-1][i + (1 << (k-1))][j]);
  184.                 }
  185.             }
  186.         }
  187.     }
  188.     rectangles2.clear();
  189.     for (auto [i, j, h, w] : rectangles) {
  190.         if (RMQ(Right, j-1, i, i+h-1) > w) rectangles2.emplace_back(i, j, h, w);
  191.     }
  192.     rectangles = rectangles2;
  193.  
  194.     // Up
  195.     for (int i = 0; i < n; ++i) { // row
  196.         for (int j = 0; j < m; ++j) reachRMQ[0][i][j] = reach[2][i][j];
  197.         for (int k = 1; k <= LG; ++k) {
  198.             for (int j = 0; j < m; ++j) {
  199.                 int j2 = j + (1 << (k-1));
  200.                 if (j2 >= m) {
  201.                     reachRMQ[k][i][j] = reachRMQ[k-1][i][j];
  202.                 } else {
  203.                     reachRMQ[k][i][j] = min(reachRMQ[k-1][i][j], reachRMQ[k-1][i][j + (1 << (k-1))]);
  204.                 }
  205.             }
  206.         }
  207.     }
  208.     rectangles2.clear();
  209.     for (auto [i, j, h, w] : rectangles) {
  210.         if (RMQ(Up, i+h, j, j+w-1) > h) rectangles2.emplace_back(i, j, h, w);
  211.     }
  212.     rectangles = rectangles2;
  213.  
  214.     // Down
  215.     for (int i = 0; i < n; ++i) { // row
  216.         for (int j = 0; j < m; ++j) reachRMQ[0][i][j] = reach[3][i][j];
  217.         for (int k = 1; k <= LG; ++k) {
  218.             for (int j = 0; j < m; ++j) {
  219.                 int j2 = j + (1 << (k-1));
  220.                 if (j2 >= m) {
  221.                     reachRMQ[k][i][j] = reachRMQ[k-1][i][j];
  222.                 } else {
  223.                     reachRMQ[k][i][j] = min(reachRMQ[k-1][i][j], reachRMQ[k-1][i][j + (1 << (k-1))]);
  224.                 }
  225.             }
  226.         }
  227.     }
  228.     rectangles2.clear();
  229.     for (auto [i, j, h, w] : rectangles) {
  230.         if (RMQ(Down, i-1, j, j+w-1) > h) rectangles2.emplace_back(i, j, h, w);
  231.     }
  232.     rectangles = rectangles2;
  233.    
  234.     return rectangles.size();
  235. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement