(*** PICTURE - PASCAL version 2 ps@di.fct.unl.pt ***) program Pictures (output); type pRect = ^rectangle; rectangle = record xmin, ymin, xmax, ymax: integer; next: pRect end; pEdge = ^edge; edge = record {vertical edges} kind: (left, right); finish: boolean; x, ymin, ymax: integer; next: pEdge end; var LRy, R: pRect; { LRy = list of rectangles } LEx: pEdge; i, N, yminG, ymaxG, intRect, boundRect: integer; f, g: text; Perimeter: longint; procedure update (ymin, ymax: integer; var yminG, ymaxG: integer); begin if ymin < yminG then yminG := ymin; if ymax > ymaxG then ymaxG := ymax end; procedure insertRect (var Ly, R: pRect); var pointer, previous: pRect; less: boolean; begin if Ly = nil then begin R^.next := nil; Ly := R end else begin less := true; pointer := Ly; previous := Ly; while (pointer <> nil) and less do begin if pointer^.ymin >= R^.ymin then less := false else begin previous := pointer; pointer := pointer^.next end end; if pointer = Ly then Ly := R else previous^.next := R; R^.next := pointer end end; procedure selectEdges (y: integer; var LRy: pRect; var LEx: pEdge); var LRAux: pRect; E: pEdge; greater: boolean; procedure insertEdge (E: pEdge; var LEx: pEdge); var LEAux, previous: pEdge; less: boolean; begin {ascending order in x} if LEx = nil then begin E^.next := nil; LEx := E end else begin less := true; LEAux := LEx; previous := LEx; while (LEAux <> nil) and less do if LEAux^.x >= E^.x then less := false else begin previous := LEAux; LEAux := LEAux^.next end; if LEAux = LEx then LEx := E else previous^.next := E; E^.next := LEAux end end; begin {selectEdges} greater := false; while (LRy <> nil) and (not greater) do if LRy^.ymin = y then begin LRAux := LRy; new(E); E^.kind := left; E^.finish := false; E^.x := LRy^.xmin; E^.ymin := LRy^.ymin; E^.ymax := LRy^.ymax; insertEdge(E, LEx); new(E); E^.kind := right; E^.finish := false; E^.x := LRy^.xmax; E^.ymin := LRy^.ymin; E^.ymax := LRy^.ymax; insertEdge(E, LEx); LRy := LRy^.next; dispose(LRAux) end else greater := true end; procedure deleteEdges (y: integer; var LEx: pEdge); var aux, prev: pEdge; found: boolean; begin {delete edges with ymax=y-1; mark edges with ymax=y} aux := LEx; {LEx<>nil } repeat found := aux^.ymax = y - 1; if found then begin aux := aux^.next; dispose(LEx); LEx := aux end until (aux = nil) or (not found); prev := aux; while aux <> nil do if aux^.ymax = y - 1 then if prev <> aux then begin prev^.next := aux^.next; dispose(aux); aux := prev^.next end else begin LEx := aux^.next; prev := LEx; dispose(aux); aux := LEx end else begin aux^.finish := aux^.ymax = y; prev := aux; aux := aux^.next end end; procedure scanEdges (y: integer; Lx: pEdge); var intRect, oldIntRect, totalRect, oldTotalRect, lowBRect, oldLowBRect, subtR, oldSubtR: integer; prev: pEdge; first: boolean; begin intRect := 0; oldIntRect := 0; totalRect := 0; oldTotalRect := 0; lowBRect := 0; oldLowBRect := 0; subtR := 0; oldSubtR := 0; prev := Lx; first := true; repeat if Lx^.finish then if Lx^.kind = left then subtR := subtR + 1 else subtR := subtR - 1 else begin if Lx^.kind = left then begin totalRect := totalRect + 1; if Lx^.ymax > y + 1 then intRect := intRect + 1; if Lx^.ymin = y then lowBRect := lowBRect + 1 end else {right edge} begin totalRect := totalRect - 1; if Lx^.ymax > y + 1 then intRect := intRect - 1; if Lx^.ymin = y then lowBRect := lowBRect - 1 end; if (totalRect = 0) and (oldTotalRect = 1) then Perimeter := Perimeter + 1 else if (totalRect = 1) and (oldTotalRect = 0) then if not first and (prev^.x = Lx^.x) and not prev^.finish then Perimeter := Perimeter - 1 else Perimeter := Perimeter + 1; if (oldIntRect = 0) and (oldTotalRect > 0) then Perimeter := Perimeter + Lx^.x - prev^.x; if (oldLowBRect > 0) and (oldTotalRect = oldLowBRect) then begin Perimeter := Perimeter + Lx^.x - prev^.x; if oldSubtR > 0 then Perimeter := Perimeter - 2 * (Lx^.x - prev^.x) end end; oldIntRect := intRect; oldTotalRect := totalRect; oldLowBRect := lowBRect; oldSubtR := subtR; first := false; prev := Lx; Lx := Lx^.next until Lx = nil end; begin { MAIN } assign(f, 'PICTURE.IN'); reset(f); Perimeter := 0; read(f, N); new(R); with R^ do begin read(f, xmin, ymin, xmax, ymax); yminG := ymin; ymaxG := ymax end; LRy := nil; insertRect(LRy, R); for i := 2 to N do begin new(R); with R^ do begin read(f, xmin, ymin, xmax, ymax); update(ymin, ymax, yminG, ymaxG) end; insertRect(LRy, R) end; close(f); LEx := nil; for i := yminG to ymaxG do begin selectEdges(i, LRy, LEx); if LEx <> nil then begin deleteEdges(i, LEx); if LEx <> nil then scanEdges(i, LEx); end end; writeln('Perimeter=', Perimeter : 1); assign(g, 'PICTURE.OUT'); rewrite(g); writeln(g, Perimeter:1); close(g) end.