#include #include #include #include #include #include #include #include #include #define XDBG if (0) //#define XDBG if (1) int V, N, H; struct husto { int xl, xr, yb, yt; } *husto; struct bod { int x, y; } *body; // Vzdálenost mezi dvěma body #define draha(A, B) sqrt((double)(A.x - B.x)*(A.x - B.x) + (double)(A.y - B.y)*(A.y - B.y)) #define A body[a] #define B body[b] #define L husto[l] // Vzdálenost, kterou stráví úsečka v lese #define OUT(d) do { double dd = d; XDBG printf("%u %u %u -> %lf\n", a, b, l, dd); return dd; } while (0) //#define OUT(d) return d double uhusto(unsigned a, unsigned b, unsigned l) { // Když je úsečka úplně mimo, tak ji nemusíme zkoumat vůbec if ((A.x < L.xl) && (B.x < L.xl) || (A.x > L.xr) && (B.x > L.xr) || (A.y < L.yb) && (B.y < L.yb) || (A.y > L.yt) && (B.y > L.yt) ) OUT(0); // Do pole Z si uložíme body, mezi kterými pak budeme počítat vzdálenost struct bod Z[6]; unsigned zn = 0; // Je nějaký krajní bod uvnitř hustolesa? if (A.x > L.xl && A.x < L.xr && A.y > L.yb && A.y < L.yt) Z[zn++] = A; if (B.x > L.xl && B.x < L.xr && B.y > L.yb && B.y < L.yt) Z[zn++] = B; // Oba jsou uvnitř if (zn == 2) OUT(draha(A, B)); // Směrnice úsečky double yx = (double)(B.y - A.y) / (B.x - A.x); double xy = (double)(B.x - A.x) / (B.y - A.y); // Průsečíky s jednotlivými hranami // levá a pravá (souřadnice y) double yl = A.y + (double)(L.xl - A.x) * (B.y - A.y) / (B.x - A.x); double yr = A.y + (double)(L.xr - A.x) * (B.y - A.y) / (B.x - A.x); // horní a dolní (souřadnice x) double xh = A.x + (double)(L.yt - A.y) * (B.x - A.x) / (B.y - A.y); double xd = A.x + (double)(L.yb - A.y) * (B.x - A.x) / (B.y - A.y); if (((L.xl <= A.x) + (L.xl <= B.x) == 1) && (yl > L.yb && yl <= L.yt)) Z[zn++] = (struct bod) { L.xl, yl }; if (((L.xr <= A.x) + (L.xr <= B.x) == 1) && (yr >= L.yb && yr < L.yt)) Z[zn++] = (struct bod) { L.xr, yr }; if (((L.yt <= A.y) + (L.yt <= B.y) == 1) && (xh > L.xl && xh <= L.xr)) Z[zn++] = (struct bod) { xh, L.yt }; if (((L.yb <= A.y) + (L.yb <= B.y) == 1) && (xd >= L.xl && xd < L.xr)) Z[zn++] = (struct bod) { xd, L.yb }; ASSERT(zn <= 2); if (zn == 2) OUT(draha(Z[0], Z[1])); else OUT(0); } #undef A #undef B #undef L struct event { int y, xl, xr; int s, id; }; #define TREE_NODE struct event #define TREE_PREFIX(x) ev_##x #define TREE_DUPLICATES #define TREE_KEY_COMPLEX(e) e y, e s #define TREE_KEY_DECL int y, int s #define TREE_GIVE_CMP static inline int ev_cmp(int ya, int ta, int yb, int tb) { if (ya < yb) return -1; if (ya > yb) return 1; if (ta < tb) return -1; if (ta > tb) return 1; return 0; } static inline int ev_cmp_sort(const void *a, const void *b) { const struct event *A = a, *B = b; return ev_cmp(A->y, A->s, B->y, B->s); } #define TREE_GIVE_INIT_KEY static inline int ev_init_key(struct event *ev, int y, int s) { ev->y = y; ev->s = s; } #define TREE_WANT_BOUNDARY #define TREE_WANT_ADJACENT #define TREE_WANT_CLEANUP #define TREE_WANT_NEW #define TREE_WANT_REMOVE #define TREE_WANT_FIND #define TREE_WANT_FIND_NEXT #define TREE_WANT_DUMP static inline void ev_dump_key(struct fastbuf *fb, struct event *ev) { bprintf(fb, "%d: ", ev->y); } static inline void ev_dump_data(struct fastbuf *fb, struct event *ev) { bprintf(fb, "(%+d %d) %d %d", ev->s, ev->id, ev->xl, ev->xr); } #include struct interval { int xl, xr; int id; }; #define TREE_NODE struct interval #define TREE_PREFIX(x) int_##x #define TREE_KEY_COMPLEX(i) i xl, i xr #define TREE_KEY_DECL int xl, int xr #define TREE_GIVE_CMP static inline int int_cmp(int xla, int xra, int xlb, int xrb) { ASSERT(xla <= xra); ASSERT(xlb <= xrb); if (xra <= xlb) return -1; if (xla >= xrb) return 1; return 0; } #define TREE_GIVE_INIT_KEY static inline void int_init_key(struct interval *i, int xl, int xr) { i->xl = xl; i->xr = xr; } #define TREE_WANT_FIND #define TREE_WANT_SEARCH_UP #define TREE_WANT_SEARCH_DOWN #define TREE_WANT_CLEANUP #define TREE_WANT_NEW #define TREE_WANT_REMOVE #define TREE_WANT_DUMP static inline void int_dump_key(struct fastbuf *fb, struct interval *i) { bprintf(fb, "%d %d -> ", i->xl, i->xr); } static inline void int_dump_data(struct fastbuf *fb, struct interval *i) { bprintf(fb, "%d", i->id); } #include #define RAND(min, max) ((min) + (rand() % ((max) - (min)))) int main(void) { scanf("%d %d %d\n", &V, &N, &H); body = malloc(sizeof(struct bod) * N); husto = malloc(sizeof(struct husto) * H); for (int i=0; i 0) : (ew[w].s < 0)) \ int_new(&intt, ew[w].xl, ew[w].xr)->id = ew[w].id; \ else { \ struct interval *in = int_find(&intt, ew[w].xl, ew[w].xr); \ ASSERT(in); \ int_remove(&intt, in); \ } \ } while(0) #define ZPET KROK(0) #define TAM KROK(1) int w = 0; /* 0 -> InT ještě neobsahuje nic * 1 -> InT obsahuje dummy interval * 5 -> InT má zpracovaných první 4 události * H*2 -> InT čeká na poslední událost * H*2+1 -> InT obsahuje už jen dummy * H*2+2 -> InT už neobsahuje ani dummy * to, na co w ukazuje, v InT "ještě" není */ for ( ; (ew[w].y < body[0].y) || (ew[w].y == body[0].y) && (ew[w].s == -1); w++) TAM; double d = 0; int lastdir = 1; for (int i=1; i body[i-1].y); int xdir = (body[i].x > body[i-1].x); int lastx = body[i-1].x; int newx; for ( w -= (1-newdir) ; (newdir ? (ew[w].y < body[i].y) : (ew[w].y > body[i].y)) || (ew[w].y == body[i].y) && (ew[w].s == (newdir ? -1 : 1)) ; w += (newdir ? 1 : -1)) { if (ew[w].s == (newdir ? 1 : -1)) KROK(newdir); fesetround(xdir ? FE_UPWARD : FE_DOWNWARD); newx = body[i-1].x + lrint((double)(body[i].x - body[i-1].x)*(ew[w].y - body[i-1].y)/(body[i].y - body[i-1].y)); while (1) { struct interval *in = (xdir ? int_search_up : int_search_down)(&intt, lastx, lastx); if ((!in) || (in->id == -1)) break; if (xdir ? (in->xl >= newx) : (in->xr <= newx)) break; double add = uhusto(i, i-1, in->id); if (add) if (rect == -1) { rect = in->id; d += add; XDBG printf("\t add %lf\n", add); } else ASSERT(rect == in->id); lastx = xdir ? in->xr : in->xl; } fesetround(xdir ? FE_DOWNWARD : FE_UPWARD); lastx = body[i-1].x + lrint((double)(body[i].x - body[i-1].x)*(ew[w].y - body[i-1].y)/(body[i].y - body[i-1].y)); if (ew[w].s == (newdir ? -1 : 1)) KROK(newdir); } if (!newdir) w++; newx = body[i].x; while (1) { struct interval *in = (xdir ? int_search_up : int_search_down)(&intt, lastx, lastx); if ((!in) || (in->id == -1)) break; if (xdir ? (in->xl >= newx) : (in->xr <= newx)) break; double add = uhusto(i, i-1, in->id); if (add) if (rect == -1) { rect = in->id; d += add; XDBG printf("\t add %lf\n", add); } else ASSERT(rect == in->id); lastx = xdir ? in->xr : in->xl; } for ( ; (ew[w].y < body[i].y) || (ew[w].y == body[i].y) && (ew[w].s == -1); w++) TAM; for (w-- ; (ew[w].y > body[i].y) || (ew[w].y == body[i].y) && (ew[w].s == 1); w--) ZPET; w++; lastdir = newdir; } fesetround(FE_TONEAREST); printf("%.0lf\n", d/V); }