def is_simple(polygon): """Test if a rectilinear polygon is is_simple :param polygon: list of points as (x,y) pairs along the closed polygon :returns: True if the segements do not intersect :complexity: O(n log n) for n=len(polygon) """ n = len(polygon) order = list(range(n)) order.sort(key=lambda i: polygon[i]) # ordre lexicographique rank_to_y = list(set(p[1] for p in polygon)) rank_to_y.sort() y_to_rank = {rank_to_y[i]: i for i in range(len(rank_to_y))} S = RangeMinQuery([0] * len(rank_to_y)) # structure balayage for i in order: x, y = polygon[i] rank = y_to_rank[y] # -- type de point right_x = max(polygon[i - 1][0], polygon[(i + 1) % n][0]) left = x < right_x below_y = min(polygon[i - 1][1], polygon[(i + 1) % n][1]) high = y > below_y if left: # il ne faut pas encore y dans S if S[rank]: return False # inters. entre deux segm. horiz. S[rank] = -1 # ajouter y à S else: S[rank] = 0 # enlever y de S if high: lo = y_to_rank[below_y] # vérifier S entre lo + 1 et rank - 1 if (below_y != last_y or last_y == y or rank - lo >= 2 and S.range_min(lo + 1, rank)): return False # inters. entre segm. horiz. et vertic. last_y = y # mémoriser pour prochaine itération return True
def __init__(self, graph): """builds the structure from a given tree :param graph: adjacency matrix of a tree :complexity: O(n log n), with n = len(graph) """ n = len(graph) dfs_trace = [] self.last = [None] * n to_visit = [(0, 0, None)] # sommet 0 est la racine next = [0] * n while to_visit: level, node, father = to_visit[-1] self.last[node] = len(dfs_trace) dfs_trace.append((level, node)) if next[node] < len(graph[node]) and \ graph[node][next[node]] == father: next[node] += 1 if next[node] == len(graph[node]): to_visit.pop() else: neighbor = graph[node][next[node]] next[node] += 1 to_visit.append((level + 1, neighbor, node)) self.rmq = RangeMinQuery(dfs_trace, (float('inf'), None))
def is_simple(polygon): """Test if a rectilinear polygon is is_simple :param polygon: list of points as (x,y) pairs along the closed polygon :returns: True if the segements do not intersect :complexity: O(n log n) for n=len(polygon) """ n = len(polygon) order = list(range(n)) order.sort(key=lambda i: polygon[i]) # lexicographic order rank_to_y = list(set(p[1] for p in polygon)) rank_to_y.sort() y_to_rank = {y: rank for rank, y in enumerate(rank_to_y)} S = RangeMinQuery([0] * len(rank_to_y)) # sweep structure last_y = None for i in order: x, y = polygon[i] rank = y_to_rank[y] # -- type of point right_x = max(polygon[i - 1][0], polygon[(i + 1) % n][0]) left = x < right_x below_y = min(polygon[i - 1][1], polygon[(i + 1) % n][1]) high = y > below_y if left: # y does not need to be in S yet if S[rank]: return False # two horizontal segments intersect S[rank] = -1 # add y to S else: S[rank] = 0 # remove y from S if high: lo = y_to_rank[below_y] # check S between [lo + 1, rank - 1] if (below_y != last_y or last_y == y or rank - lo >= 2 and S.range_min(lo + 1, rank)): return False # horiz. & vert. segments intersect last_y = y # remember for next iteration return True
class LowestCommonAncestorRMQ: """Lowest common ancestor data structure using a reduction to range minimum query """ def __init__(self, graph): """builds the structure from a given tree :param graph: adjacency matrix of a tree :complexity: O(n log n), with n = len(graph) """ n = len(graph) dfs_trace = [] self.last = [None] * n to_visit = [(0, 0, None)] # sommet 0 est la racine next = [0] * n while to_visit: level, node, father = to_visit[-1] self.last[node] = len(dfs_trace) dfs_trace.append((level, node)) if next[node] < len(graph[node]) and \ graph[node][next[node]] == father: next[node] += 1 if next[node] == len(graph[node]): to_visit.pop() else: neighbor = graph[node][next[node]] next[node] += 1 to_visit.append((level + 1, neighbor, node)) self.rmq = RangeMinQuery(dfs_trace, (float('inf'), None)) def query(self, u, v): """:returns: the lowest common ancestor of u and v :complexity: O(log n) """ lu = self.last[u] lv = self.last[v] if lu > lv: lu, lv = lv, lu return self.rmq.range_min(lu, lv + 1)[1]