fork download
  1. //Credit: anton_lunyov
  2.  
  3. // Supports the following types of queries on the string S:
  4. // - match(q) - returns the number of occurrences of the string `q` in S,
  5. // complexity is O(|q| * log |S|).
  6. // - pop() - deletes the first character of S and returns its value,
  7. // complexity is O(log |S|).
  8. // - push(c) - inserts character `c` at the beginning of the string,
  9. // complexity is O(log^2 |S|).
  10. // - size() - returns the length of the string,
  11. // complexity is O(1).
  12. // - at(i) - returns the i-th character of S in 0-based numeration,
  13. // complexity is O(1).
  14. // - revat(i) - returns the i-th character of S reversed (in 0-based numeration),
  15. // it will be convenient for the main class StringDeque,
  16. // complexity is O(1).
  17. // Occupies O(|S|) memory at each moment.
  18. class DynamicSuffixArray {
  19. private:
  20. // The data structure for node of the treap.
  21. struct Node {
  22. int left, right, parent;
  23. int size; // The size of the subtree.
  24. int y; // The key for heap ordering.
  25.  
  26. // Creates node having all zero links, but with size 1.
  27. // We will call such node as default node.
  28. // rand() for y keeps the tree self-balancing.
  29. Node(): y(rand()), left(0), right(0), parent(0), size(1) {};
  30. };
  31.  
  32. // Node nodes_[id] corresponds to the suffix that starts at str_[id].
  33. vector<char> str_; // The actual string in reversed order.
  34. vector<Node> nodes_; // The nodes of the treap.
  35. int root_; // nodes_[root_] is the root of the treap.
  36.  
  37. public:
  38. // Creates dummy zero character and zero node, and sets root to 0.
  39. DynamicSuffixArray() {
  40. str_.push_back(0);
  41. nodes_.push_back(Node());
  42. nodes_[0].size = 0; // The size is 1 by default so we fix this.
  43. root_ = 0; // Indicates that the tree is empty.
  44. }
  45. // To construct dynamic suffix array by string we should push all characters
  46. // of the string in reversed order. So complexity is O(|S| * log^2 |S|).
  47. // TODO: Implement a constructor by string using usual suffix array
  48. // with complexity O(|S| * log |S|) or even O(|S|).
  49.  
  50. // Returns the number of occurrences of the string `q` in the string S.
  51. int match(const string& q) {
  52. return match(root_, q, false, false);
  53. }
  54.  
  55. // Deletes the first character of the string and returns its value.
  56. char pop() {
  57. remove(size()); // Removes last node from the tree and updates the root.
  58. nodes_.pop_back();
  59. char c = str_.back();
  60. str_.pop_back();
  61. return c;
  62. }
  63.  
  64. // Inserts character `c` to the beginning of the string.
  65. void push(char c) {
  66. str_.push_back(c); // We add `c` to the array `str_`.
  67. nodes_.push_back(Node()); // We add default node to the array `nodes_`...
  68. // ...and then actually insert this node to the tree and update the root.
  69. // We pass the order statistic of (id-1)-th suffix to speed up the solution.
  70. int id = size();
  71. root_ = insert(root_, id, getIndex(id - 1));
  72. }
  73.  
  74. // Returns the length of the string.
  75. int size() {
  76. return str_.size() - 1; // "-1" because of the dummy zero character.
  77. }
  78.  
  79. // Returns the i-th character of the string in 0-based numeration.
  80. char at(int i) {
  81. // Recall that the 0-th character of S is `size()`-th character in `str_`.
  82. return str_[size() - i];
  83. }
  84.  
  85. // Returns the i-th character of the reversed string in 0-based numeration.
  86. char revat(int i) {
  87. return str_[i + 1]; // "+1" because of the dummy zero character.
  88. }
  89.  
  90. private:
  91. // See editorial for details.
  92. int match(int tree, const string& q, bool matchLeft, bool matchRight) {
  93. // For empty subtree the answer is 0.
  94. if (!tree) {
  95. return 0;
  96. }
  97. // In this case all suffixes in subtree start with `q`.
  98. if (matchLeft && matchRight) {
  99. // So the answer is the size of this subtree.
  100. return nodes_[tree].size;
  101. }
  102. for (int i = 0; i < q.size(); ++i) {
  103. if (q[i] > str_[tree - i]) {
  104. // Here `matchLeft` should be set to false.
  105. return match(nodes_[tree].right, q, false, matchRight);
  106. } else if (q[i] < str_[tree - i]) {
  107. // While here `matchRight` should be set to false.
  108. return match(nodes_[tree].left, q, matchLeft, false);
  109. }
  110. }
  111. return 1 +
  112. match(nodes_[tree].left, q, matchLeft, true) +
  113. match(nodes_[tree].right, q, true, matchRight);
  114. }
  115.  
  116. // Sets parent of node `id` to `parent_id` if `id` is non-zero.
  117. void setParent(int id, int parent_id) {
  118. if (id) {
  119. nodes_[id].parent = parent_id;
  120. }
  121. }
  122.  
  123. // Sets field `size` of the node `id` to the actual size of its subtree.
  124. // Modifies only non-zero nodes.
  125. void fixSize(int id) {
  126. if (id) {
  127. nodes_[id].size = 1 +
  128. nodes_[nodes_[id].left].size +
  129. nodes_[nodes_[id].right].size;
  130. }
  131. }
  132.  
  133. // Removes node `id` from the tree and update the root.
  134. // Vector `nodes_` does not change.
  135. void remove(int id) {
  136. int par = nodes_[id].parent;
  137. int tmp = merge(nodes_[id].left, nodes_[id].right);
  138. // `tmp` is id of node that contains merge of children of the node `id`.
  139. // `par` is the parent of `tmp` since `tmp` is replacement of `id`.
  140. setParent(tmp, par);
  141. if (par) {
  142. // If `id` has parent then root remains the same,
  143. // but we need to replace `id` by `tmp` in sons of the node `par`.
  144. if(nodes_[par].left == id) {
  145. nodes_[par].left = tmp;
  146. } else {
  147. nodes_[par].right = tmp;
  148. }
  149. while (par) {
  150. // Since we delete one node in subtree of `id`,
  151. // we should decrease the field `size` of each its ancestor by 1.
  152. nodes_[par].size--;
  153. par = nodes_[par].parent;
  154. }
  155. } else {
  156. // Otherwise `id` was the root and the new root is `tmp`.
  157. root_ = tmp;
  158. }
  159. }
  160.  
  161. // Merges subtrees rooted at `L` and `R` and save result in one of the them.
  162. // Each node in the subtree rooted at `L` should be less than
  163. // each node in the subtree rooted at `R`.
  164. int merge(int L, int R) {
  165. // We return L when R is 0 and R when L is 0.
  166. if (!L || !R) {
  167. return L + R;
  168. }
  169. // We should preserve the heap property by field `y`.
  170. if (nodes_[L].y < nodes_[R].y) {
  171. // In this case `R` should be a root and we merge `L` and left son of `R`,
  172. // and result is saved in `tmp`.
  173. int tmp = merge(L, nodes_[R].left);
  174. // `tmp` will be the new left son of `R`.
  175. setParent(tmp, R);
  176. nodes_[R].left = tmp;
  177. fixSize(R);
  178. return R;
  179. } else {
  180. // In this case `L` will be a root.
  181. int tmp = merge(nodes_[L].right, R);
  182. setParent(tmp, L);
  183. nodes_[L].right = tmp;
  184. fixSize(L);
  185. return L;
  186. }
  187. }
  188.  
  189. // Returns the index of `id`-th suffix (the suffix starting at position `id`)
  190. // in the sorted array of all suffixes (empty suffix has index 0),
  191. // the so-called order statistic of the suffix.
  192. int getIndex(int id) {
  193. // Zero node corresponds to empty suffix and has zero index.
  194. if (!id) {
  195. return 0;
  196. }
  197. // We add one more the size of its left subtree to the answer.
  198. int index = nodes_[nodes_[id].left].size + 1;
  199. while (nodes_[id].parent) {
  200. int par = nodes_[id].parent; // Ancestor of the initial node `id`
  201. if (id == nodes_[par].right) {
  202. // If node `id` is the right son of `par`,
  203. // we add one more the size of left subtree of `par` to the answer as above.
  204. index += nodes_[nodes_[par].left].size + 1;
  205. }
  206. id = par;
  207. }
  208. return index;
  209. }
  210.  
  211. // Returns result of comparison of id1-th and id2-th suffixes.
  212. // Result is negative if id1-th suffix smaller, positive if it's larger,
  213. // and zero when they are equal (i.e. when id1 = id2).
  214. // It is not assumed these suffixes has correct positions in the tree,
  215. // but (id1-1)-th and (id2-1)-th suffixes should have ones.
  216. // `index1` is the order statistic of (id1-1)-th suffix.
  217. int compare(int id1, int id2, int index1) {
  218. // At first we compare their first characters.
  219. int cmp = str_[id1] - str_[id2];
  220. if (cmp == 0)
  221. // If they are different we compare order statistics
  222. // for (i-1)-th and (j-1)-th suffixes.
  223. cmp = index1 - getIndex(id2 - 1);
  224. return cmp;
  225. }
  226.  
  227. // Inserts node `id` to the subtree rooted at `tree`
  228. // and returns the new root of this subtree (it may change).
  229. // `index1` is the order statistic of (id-1)-th suffix.
  230. int insert(int tree, int id, int index1) {
  231. // In the case of empty subtree the node `id` will be a new root.
  232. if (!tree) {
  233. return id;
  234. }
  235. // The treap should be a heap by `y` fields.
  236. // Hence if `id` has larger `y` than `tree`, `id` should be a new root.
  237. if (nodes_[tree].y < nodes_[id].y) {
  238. // In this case we split subtree rooted at `tree` into two parts:
  239. // 1) with suffixes < the `id`-th suffix (the root is left son of `id`);
  240. // 2) with suffixes > the `id`-th suffix (the root is right son of `id`).
  241. split(tree, id, index1, nodes_[id].left, nodes_[id].right);
  242. // We set parents of both left and right sons if `id` to be `id`.
  243. setParent(nodes_[id].left, id);
  244. setParent(nodes_[id].right, id);
  245. fixSize(id);
  246. return id; // This case is terminal for insert query.
  247. }
  248. // Otherwise we should move `id` to one of the subtrees of the node `tree`,
  249. // selecting the correct subtree by comparing suffixes at `tree` and `id`.
  250. int cmp = compare(id, tree, index1);
  251. if (cmp < 0) {
  252. // If `id` is less than `tree` than we insert it to the left subtree.
  253. // `tmp` is the root of this subtree after inserting.
  254. int tmp = insert(nodes_[tree].left, id, index1);
  255. // And since root of this subtree could change,
  256. // we fix relation between `tree` and `tmp`
  257. setParent(tmp, tree);
  258. nodes_[tree].left = tmp;
  259. } else {
  260. // Now cmp > 0 since all suffixes are different
  261. // and we insert `id` to the right subtree.
  262. int tmp = insert(nodes_[tree].right, id, index1);
  263. setParent(tmp, tree);
  264. nodes_[tree].right = tmp;
  265. }
  266. // We should fix the field `size` of the node `tree`.
  267. // We can simply increase it by 1 since we add only one node to its subtree.
  268. nodes_[tree].size++;
  269. return tree; // `tree` remains the root of its subtree
  270. }
  271.  
  272. // Splits the subtree rooted at `tree` by the node `id` into two parts:
  273. // 1) with suffixes < the `id`-th suffix (the root is `L`);
  274. // 2) with suffixes > the `id`-th suffix (the root is `R`).
  275. // `id`-th node does not have to be a correct node of the tree.
  276. // But node `id - 1` should be.
  277. // `index1` is the order statistic of (id-1)-th suffix.
  278. void split(int tree, int id, int index1, int& L, int& R) {
  279. // In the case of empty subtree there is nothing to split,
  280. // and both `L` and `R` should be empty trees as well.
  281. if (!tree) {
  282. L = R = 0;
  283. return;
  284. }
  285. // Otherwise we compare the root of the subtree with the node `id`.
  286. int cmp = compare(id, tree, index1);
  287. if (cmp < 0) {
  288. // If `id` < `tree` then we should split left subtree of `tree` by `id`
  289. // and place the second subtree to the root of left subtree itself,
  290. split(nodes_[tree].left, id, index1, L, nodes_[tree].left);
  291. setParent(nodes_[tree].left, tree);
  292. R = tree;
  293. } else {
  294. // Otherwise cmp > 0 and we split right subtree by the node `id`.
  295. split(nodes_[tree].right, id, index1, nodes_[tree].right, R);
  296. setParent(nodes_[tree].right, tree);
  297. L = tree;
  298. }
  299. fixSize(tree);
  300. }
  301. };
  302.  
  303.  
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.cpp:33:3: error: ‘vector’ does not name a type
   vector<char> str_;    // The actual string in reversed order.
   ^~~~~~
prog.cpp:34:3: error: ‘vector’ does not name a type
   vector<Node> nodes_;  // The nodes of the treap.
   ^~~~~~
prog.cpp:51:19: error: ‘string’ does not name a type; did you mean ‘struct’?
   int match(const string& q) {
                   ^~~~~~
                   struct
prog.cpp:92:29: error: ‘string’ does not name a type; did you mean ‘struct’?
   int match(int tree, const string& q, bool matchLeft, bool matchRight) {
                             ^~~~~~
                             struct
prog.cpp: In constructor ‘DynamicSuffixArray::Node::Node()’:
prog.cpp:29:15: error: ‘rand’ was not declared in this scope
     Node(): y(rand()), left(0), right(0), parent(0), size(1) {};
               ^~~~
prog.cpp: In constructor ‘DynamicSuffixArray::DynamicSuffixArray()’:
prog.cpp:40:5: error: ‘str_’ was not declared in this scope
     str_.push_back(0);
     ^~~~
prog.cpp:40:5: note: suggested alternative: ‘std’
     str_.push_back(0);
     ^~~~
     std
prog.cpp:41:5: error: ‘nodes_’ was not declared in this scope
     nodes_.push_back(Node());
     ^~~~~~
prog.cpp:41:5: note: suggested alternative: ‘Node’
     nodes_.push_back(Node());
     ^~~~~~
     Node
prog.cpp: In member function ‘char DynamicSuffixArray::pop()’:
prog.cpp:58:5: error: ‘nodes_’ was not declared in this scope
     nodes_.pop_back();
     ^~~~~~
prog.cpp:58:5: note: suggested alternative: ‘Node’
     nodes_.pop_back();
     ^~~~~~
     Node
prog.cpp:59:14: error: ‘str_’ was not declared in this scope
     char c = str_.back();
              ^~~~
prog.cpp:59:14: note: suggested alternative: ‘std’
     char c = str_.back();
              ^~~~
              std
prog.cpp: In member function ‘void DynamicSuffixArray::push(char)’:
prog.cpp:66:5: error: ‘str_’ was not declared in this scope
     str_.push_back(c);         // We add `c` to the array `str_`.
     ^~~~
prog.cpp:66:5: note: suggested alternative: ‘std’
     str_.push_back(c);         // We add `c` to the array `str_`.
     ^~~~
     std
prog.cpp:67:5: error: ‘nodes_’ was not declared in this scope
     nodes_.push_back(Node());  // We add default node to the array `nodes_`...
     ^~~~~~
prog.cpp:67:5: note: suggested alternative: ‘Node’
     nodes_.push_back(Node());  // We add default node to the array `nodes_`...
     ^~~~~~
     Node
prog.cpp: In member function ‘int DynamicSuffixArray::size()’:
prog.cpp:76:12: error: ‘str_’ was not declared in this scope
     return str_.size() - 1;  // "-1" because of the dummy zero character.
            ^~~~
prog.cpp:76:12: note: suggested alternative: ‘std’
     return str_.size() - 1;  // "-1" because of the dummy zero character.
            ^~~~
            std
prog.cpp: In member function ‘char DynamicSuffixArray::at(int)’:
prog.cpp:82:12: error: ‘str_’ was not declared in this scope
     return str_[size() - i];
            ^~~~
prog.cpp:82:12: note: suggested alternative: ‘std’
     return str_[size() - i];
            ^~~~
            std
prog.cpp: In member function ‘char DynamicSuffixArray::revat(int)’:
prog.cpp:87:12: error: ‘str_’ was not declared in this scope
     return str_[i + 1];  // "+1" because of the dummy zero character.
            ^~~~
prog.cpp:87:12: note: suggested alternative: ‘std’
     return str_[i + 1];  // "+1" because of the dummy zero character.
            ^~~~
            std
prog.cpp: In member function ‘int DynamicSuffixArray::match(int, const int&, bool, bool)’:
prog.cpp:100:14: error: ‘nodes_’ was not declared in this scope
       return nodes_[tree].size;
              ^~~~~~
prog.cpp:100:14: note: suggested alternative: ‘Node’
       return nodes_[tree].size;
              ^~~~~~
              Node
prog.cpp:102:27: error: request for member ‘size’ in ‘q’, which is of non-class type ‘const int’
     for (int i = 0; i < q.size(); ++i) {
                           ^~~~
prog.cpp:103:14: error: invalid types ‘const int[int]’ for array subscript
       if (q[i] > str_[tree - i]) {
              ^
prog.cpp:103:18: error: ‘str_’ was not declared in this scope
       if (q[i] > str_[tree - i]) {
                  ^~~~
prog.cpp:103:18: note: suggested alternative: ‘std’
       if (q[i] > str_[tree - i]) {
                  ^~~~
                  std
prog.cpp:105:22: error: ‘nodes_’ was not declared in this scope
         return match(nodes_[tree].right, q, false, matchRight);
                      ^~~~~~
prog.cpp:105:22: note: suggested alternative: ‘Node’
         return match(nodes_[tree].right, q, false, matchRight);
                      ^~~~~~
                      Node
prog.cpp:106:21: error: invalid types ‘const int[int]’ for array subscript
       } else if (q[i] < str_[tree - i]) {
                     ^
prog.cpp:108:22: error: ‘nodes_’ was not declared in this scope
         return match(nodes_[tree].left, q, matchLeft, false);
                      ^~~~~~
prog.cpp:108:22: note: suggested alternative: ‘Node’
         return match(nodes_[tree].left, q, matchLeft, false);
                      ^~~~~~
                      Node
prog.cpp:112:13: error: ‘nodes_’ was not declared in this scope
       match(nodes_[tree].left, q, matchLeft, true) +
             ^~~~~~
prog.cpp:112:13: note: suggested alternative: ‘Node’
       match(nodes_[tree].left, q, matchLeft, true) +
             ^~~~~~
             Node
prog.cpp: In member function ‘void DynamicSuffixArray::setParent(int, int)’:
prog.cpp:119:7: error: ‘nodes_’ was not declared in this scope
       nodes_[id].parent = parent_id;
       ^~~~~~
prog.cpp:119:7: note: suggested alternative: ‘Node’
       nodes_[id].parent = parent_id;
       ^~~~~~
       Node
prog.cpp: In member function ‘void DynamicSuffixArray::fixSize(int)’:
prog.cpp:127:7: error: ‘nodes_’ was not declared in this scope
       nodes_[id].size = 1 +
       ^~~~~~
prog.cpp:127:7: note: suggested alternative: ‘Node’
       nodes_[id].size = 1 +
       ^~~~~~
       Node
prog.cpp: In member function ‘void DynamicSuffixArray::remove(int)’:
prog.cpp:136:15: error: ‘nodes_’ was not declared in this scope
     int par = nodes_[id].parent;
               ^~~~~~
prog.cpp:136:15: note: suggested alternative: ‘Node’
     int par = nodes_[id].parent;
               ^~~~~~
               Node
prog.cpp: In member function ‘int DynamicSuffixArray::merge(int, int)’:
prog.cpp:170:9: error: ‘nodes_’ was not declared in this scope
     if (nodes_[L].y < nodes_[R].y) {
         ^~~~~~
prog.cpp:170:9: note: suggested alternative: ‘Node’
     if (nodes_[L].y < nodes_[R].y) {
         ^~~~~~
         Node
prog.cpp: In member function ‘int DynamicSuffixArray::getIndex(int)’:
prog.cpp:198:17: error: ‘nodes_’ was not declared in this scope
     int index = nodes_[nodes_[id].left].size + 1;
                 ^~~~~~
prog.cpp:198:17: note: suggested alternative: ‘Node’
     int index = nodes_[nodes_[id].left].size + 1;
                 ^~~~~~
                 Node
prog.cpp: In member function ‘int DynamicSuffixArray::compare(int, int, int)’:
prog.cpp:219:15: error: ‘str_’ was not declared in this scope
     int cmp = str_[id1] - str_[id2];
               ^~~~
prog.cpp:219:15: note: suggested alternative: ‘std’
     int cmp = str_[id1] - str_[id2];
               ^~~~
               std
prog.cpp: In member function ‘int DynamicSuffixArray::insert(int, int, int)’:
prog.cpp:237:9: error: ‘nodes_’ was not declared in this scope
     if (nodes_[tree].y < nodes_[id].y) {
         ^~~~~~
prog.cpp:237:9: note: suggested alternative: ‘Node’
     if (nodes_[tree].y < nodes_[id].y) {
         ^~~~~~
         Node
prog.cpp:254:24: error: ‘nodes_’ was not declared in this scope
       int tmp = insert(nodes_[tree].left, id, index1);
                        ^~~~~~
prog.cpp:254:24: note: suggested alternative: ‘Node’
       int tmp = insert(nodes_[tree].left, id, index1);
                        ^~~~~~
                        Node
prog.cpp:262:24: error: ‘nodes_’ was not declared in this scope
       int tmp = insert(nodes_[tree].right, id, index1);
                        ^~~~~~
prog.cpp:262:24: note: suggested alternative: ‘Node’
       int tmp = insert(nodes_[tree].right, id, index1);
                        ^~~~~~
                        Node
prog.cpp:268:5: error: ‘nodes_’ was not declared in this scope
     nodes_[tree].size++;
     ^~~~~~
prog.cpp:268:5: note: suggested alternative: ‘Node’
     nodes_[tree].size++;
     ^~~~~~
     Node
prog.cpp: In member function ‘void DynamicSuffixArray::split(int, int, int, int&, int&)’:
prog.cpp:290:13: error: ‘nodes_’ was not declared in this scope
       split(nodes_[tree].left, id, index1, L, nodes_[tree].left);
             ^~~~~~
prog.cpp:290:13: note: suggested alternative: ‘Node’
       split(nodes_[tree].left, id, index1, L, nodes_[tree].left);
             ^~~~~~
             Node
prog.cpp:295:13: error: ‘nodes_’ was not declared in this scope
       split(nodes_[tree].right, id, index1, nodes_[tree].right, R);
             ^~~~~~
prog.cpp:295:13: note: suggested alternative: ‘Node’
       split(nodes_[tree].right, id, index1, nodes_[tree].right, R);
             ^~~~~~
             Node
stdout
Standard output is empty