from sys import stdin, stdout from dataclasses import dataclass n = int(stdin.readline()) perm = [int(x) - 1 for x in stdin.readline().split()] @dataclass class Rect: x_min: int x_max: int y_min: int y_max: int @property def height(self): return self.y_max - self.y_min @property def width(self): return self.x_max - self.x_min def copy(self): return self.__class__(self.x_min, self.x_max, self.y_min, self.y_max) @classmethod def prefix_rect(cls, x_max, y_max): return cls(0, x_max, 0, y_max) @classmethod def suffix_rect(cls, x_min, y_min): return cls(x_min, n, y_min, n) @dataclass class ArraySummation: rect: Rect = Rect.prefix_rect(n, n) value: int = 0 split_dir: bool = True split_val: int = n//2 parts: tuple = () def sum_rect(self, rect): if rect.width <= 0: return 0 if rect.height <= 0: return 0 return self.value + sum([child.sum_rect(splitted_rect) for child, splitted_rect in zip(self.parts, self.part_rect(rect))]) def insert(self, x, y, val=1): if (self.rect.width == 1) & (self.rect.height == 1): self.value = val return if len(self.parts) == 0: self.create_parts() insert_child = self.part_by_point(x, y) self.parts[insert_child].insert(x, y, val) def part_rect(self, rect): if len(self.parts) == 0: return [] return self.__generate_split(rect) def __generate_split(self, rect): if self.split_dir: left_r = rect.copy() right_r = rect.copy() left_r.x_max = min(rect.x_max, self.split_val) right_r.x_min = max(rect.x_min, self.split_val) return [ left_r, right_r ] else: upper_r = rect.copy() lower_r = rect.copy() upper_r.y_min = max(rect.y_min, self.split_val) lower_r.y_max = min(rect.y_max, self.split_val) return [ upper_r, lower_r ] def part_by_point(self, x, y): if self.split_dir: if x < self.split_val: return 0 else: return 1 else: if y >= self.split_val: return 0 else: return 1 def create_parts(self): self.split_dir = (self.rect.width >= self.rect.height) if self.split_dir: self.split_val = self.rect.x_min + self.rect.width // 2 else: self.split_val = self.rect.y_min + self.rect.height // 2 self.parts = tuple([self.__class__(rect=rect) for rect in self.__generate_split(self.rect)]) array_sum = ArraySummation() for k, v in enumerate(perm): array_sum.insert(k, v) def count_lines(rect): return array_sum.sum_rect(rect) res = [0] * n cache = {} min_perm = [] # min of suffix max_perm = [] # max of prefix min_perm_rev = [] # min of suffix max_perm_rev = [] # max of prefix x = -1 for i in range(n): x = max(x, perm[i]) max_perm.append(x) x = n for i in range(n-1, -1, -1): x = min(x, perm[i]) min_perm.append(x) min_perm = list(reversed(min_perm)) x = -1 for k in sorted(range(n), key=lambda x: perm[x]): x = max(x, k) max_perm_rev.append(x) x = n for k in sorted(range(n), key=lambda x: perm[x], reverse=True): x = min(x, k) min_perm_rev.append(x) min_perm_rev = list(reversed(min_perm_rev)) for i in range(n): results_to_cache = [] steps = step_lines = seen = 1 min_line = max_line = i min_target = max_target = perm[i] search = True while(search): if (min_line, max_line, min_target, max_target) in cache: cached_steps, cached_value, cached_seen = cache[(min_line, max_line, min_target, max_target)] res[i] += cached_value + (cached_seen - seen) * (steps - cached_steps) seen = cached_seen search = False continue else: results_to_cache.append(((min_line, max_line, min_target, max_target), steps, res[i])) not_crossing = (count_lines(Rect.prefix_rect(min_line, min_target)) + count_lines(Rect.suffix_rect(max_line+1, max_target+1))) step_lines = n - not_crossing - seen if step_lines == 0: search = False continue res[i] += steps * step_lines min_line, max_line, min_target, max_target = ( min_perm_rev[min_target], max_perm_rev[max_target], min_perm[min_line], max_perm[max_line]) steps += 1 seen += step_lines if seen == n: search=False if len(cache)>10**9: cache = {} for key, steps, partial_value in results_to_cache: cache[key] = (steps, res[i] - partial_value, seen) stdout.write(" ".join([str(x) for x in res]) + "\n")
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | from sys import stdin, stdout from dataclasses import dataclass n = int(stdin.readline()) perm = [int(x) - 1 for x in stdin.readline().split()] @dataclass class Rect: x_min: int x_max: int y_min: int y_max: int @property def height(self): return self.y_max - self.y_min @property def width(self): return self.x_max - self.x_min def copy(self): return self.__class__(self.x_min, self.x_max, self.y_min, self.y_max) @classmethod def prefix_rect(cls, x_max, y_max): return cls(0, x_max, 0, y_max) @classmethod def suffix_rect(cls, x_min, y_min): return cls(x_min, n, y_min, n) @dataclass class ArraySummation: rect: Rect = Rect.prefix_rect(n, n) value: int = 0 split_dir: bool = True split_val: int = n//2 parts: tuple = () def sum_rect(self, rect): if rect.width <= 0: return 0 if rect.height <= 0: return 0 return self.value + sum([child.sum_rect(splitted_rect) for child, splitted_rect in zip(self.parts, self.part_rect(rect))]) def insert(self, x, y, val=1): if (self.rect.width == 1) & (self.rect.height == 1): self.value = val return if len(self.parts) == 0: self.create_parts() insert_child = self.part_by_point(x, y) self.parts[insert_child].insert(x, y, val) def part_rect(self, rect): if len(self.parts) == 0: return [] return self.__generate_split(rect) def __generate_split(self, rect): if self.split_dir: left_r = rect.copy() right_r = rect.copy() left_r.x_max = min(rect.x_max, self.split_val) right_r.x_min = max(rect.x_min, self.split_val) return [ left_r, right_r ] else: upper_r = rect.copy() lower_r = rect.copy() upper_r.y_min = max(rect.y_min, self.split_val) lower_r.y_max = min(rect.y_max, self.split_val) return [ upper_r, lower_r ] def part_by_point(self, x, y): if self.split_dir: if x < self.split_val: return 0 else: return 1 else: if y >= self.split_val: return 0 else: return 1 def create_parts(self): self.split_dir = (self.rect.width >= self.rect.height) if self.split_dir: self.split_val = self.rect.x_min + self.rect.width // 2 else: self.split_val = self.rect.y_min + self.rect.height // 2 self.parts = tuple([self.__class__(rect=rect) for rect in self.__generate_split(self.rect)]) array_sum = ArraySummation() for k, v in enumerate(perm): array_sum.insert(k, v) def count_lines(rect): return array_sum.sum_rect(rect) res = [0] * n cache = {} min_perm = [] # min of suffix max_perm = [] # max of prefix min_perm_rev = [] # min of suffix max_perm_rev = [] # max of prefix x = -1 for i in range(n): x = max(x, perm[i]) max_perm.append(x) x = n for i in range(n-1, -1, -1): x = min(x, perm[i]) min_perm.append(x) min_perm = list(reversed(min_perm)) x = -1 for k in sorted(range(n), key=lambda x: perm[x]): x = max(x, k) max_perm_rev.append(x) x = n for k in sorted(range(n), key=lambda x: perm[x], reverse=True): x = min(x, k) min_perm_rev.append(x) min_perm_rev = list(reversed(min_perm_rev)) for i in range(n): results_to_cache = [] steps = step_lines = seen = 1 min_line = max_line = i min_target = max_target = perm[i] search = True while(search): if (min_line, max_line, min_target, max_target) in cache: cached_steps, cached_value, cached_seen = cache[(min_line, max_line, min_target, max_target)] res[i] += cached_value + (cached_seen - seen) * (steps - cached_steps) seen = cached_seen search = False continue else: results_to_cache.append(((min_line, max_line, min_target, max_target), steps, res[i])) not_crossing = (count_lines(Rect.prefix_rect(min_line, min_target)) + count_lines(Rect.suffix_rect(max_line+1, max_target+1))) step_lines = n - not_crossing - seen if step_lines == 0: search = False continue res[i] += steps * step_lines min_line, max_line, min_target, max_target = ( min_perm_rev[min_target], max_perm_rev[max_target], min_perm[min_line], max_perm[max_line]) steps += 1 seen += step_lines if seen == n: search=False if len(cache)>10**9: cache = {} for key, steps, partial_value in results_to_cache: cache[key] = (steps, res[i] - partial_value, seen) stdout.write(" ".join([str(x) for x in res]) + "\n") |