|
| 1 | +// 以下は、問題に対する **Go (Golang)** の解法です。 |
| 2 | +// 制約(点数・クエリ最大10⁵、座標範囲1500)を踏まえ、**2次元累積和(2D prefix sum)** を使って高速にクエリ処理を行います。 |
| 3 | +// 型を明示し、**実行時間とメモリ使用量を考慮**した設計です。 |
| 4 | + |
| 5 | +// ## ✅ 解法概要(再確認) |
| 6 | + |
| 7 | +// * 入力された点を `grid[x][y]` にカウント。 |
| 8 | +// * `prefix[x][y]` に (1,1)〜(x,y) の点数累積和を構築。 |
| 9 | +// * 各クエリで矩形 `[a,c] × [b,d]` の点数を O(1) で取得。 |
| 10 | + |
| 11 | +// ## ✅ Go 実装(型明示・最適化済) |
| 12 | + |
| 13 | +package main |
| 14 | + |
| 15 | +import ( |
| 16 | + "bufio" |
| 17 | + "fmt" |
| 18 | + "os" |
| 19 | + "strconv" |
| 20 | + "strings" |
| 21 | +) |
| 22 | + |
| 23 | +const SIZE = 1501 |
| 24 | + |
| 25 | +func main() { |
| 26 | + reader := bufio.NewReaderSize(os.Stdin, 1<<20) // 1MB buffer |
| 27 | + writer := bufio.NewWriter(os.Stdout) |
| 28 | + defer writer.Flush() |
| 29 | + |
| 30 | + // 数値の読み取り関数 |
| 31 | + readInt := func() int { |
| 32 | + line, _ := reader.ReadString('\n') |
| 33 | + val, _ := strconv.Atoi(strings.TrimSpace(line)) |
| 34 | + return val |
| 35 | + } |
| 36 | + |
| 37 | + readInts := func() []int { |
| 38 | + line, _ := reader.ReadString('\n') |
| 39 | + fields := strings.Fields(line) |
| 40 | + res := make([]int, len(fields)) |
| 41 | + for i, s := range fields { |
| 42 | + res[i], _ = strconv.Atoi(s) |
| 43 | + } |
| 44 | + return res |
| 45 | + } |
| 46 | + |
| 47 | + // 点の数 |
| 48 | + var N int = readInt() |
| 49 | + |
| 50 | + // grid[x][y]: 各点のカウント |
| 51 | + var grid [SIZE][SIZE]int |
| 52 | + |
| 53 | + for i := 0; i < N; i++ { |
| 54 | + p := readInts() |
| 55 | + x, y := p[0], p[1] |
| 56 | + grid[x][y]++ |
| 57 | + } |
| 58 | + |
| 59 | + // 2次元累積和の構築 |
| 60 | + var prefix [SIZE][SIZE]int |
| 61 | + |
| 62 | + for x := 1; x < SIZE; x++ { |
| 63 | + for y := 1; y < SIZE; y++ { |
| 64 | + prefix[x][y] = grid[x][y] + |
| 65 | + prefix[x-1][y] + |
| 66 | + prefix[x][y-1] - |
| 67 | + prefix[x-1][y-1] |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + // クエリ数 |
| 72 | + var Q int = readInt() |
| 73 | + |
| 74 | + for i := 0; i < Q; i++ { |
| 75 | + p := readInts() |
| 76 | + a, b, c, d := p[0], p[1], p[2], p[3] |
| 77 | + |
| 78 | + count := prefix[c][d] - |
| 79 | + prefix[a-1][d] - |
| 80 | + prefix[c][b-1] + |
| 81 | + prefix[a-1][b-1] |
| 82 | + |
| 83 | + fmt.Fprintln(writer, count) |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +// ## ✅ 実行例 |
| 88 | + |
| 89 | +// ### 入力 |
| 90 | + |
| 91 | +// ``` |
| 92 | +// 5 |
| 93 | +// 1 3 |
| 94 | +// 2 5 |
| 95 | +// 3 4 |
| 96 | +// 2 6 |
| 97 | +// 3 3 |
| 98 | +// 3 |
| 99 | +// 1 3 3 6 |
| 100 | +// 1 5 2 6 |
| 101 | +// 1 3 3 5 |
| 102 | +// ``` |
| 103 | + |
| 104 | +// ### 出力 |
| 105 | + |
| 106 | +// ``` |
| 107 | +// 5 |
| 108 | +// 2 |
| 109 | +// 4 |
| 110 | +// ``` |
| 111 | + |
| 112 | +// --- |
| 113 | + |
| 114 | +// ## ✅ 型と構造体の解説 |
| 115 | + |
| 116 | +// | 変数 | 型 | 説明 | |
| 117 | +// | ------------ | ----------------- | ------------- | |
| 118 | +// | `grid` | `[1501][1501]int` | 点の存在をカウント | |
| 119 | +// | `prefix` | `[1501][1501]int` | 2D累積和 | |
| 120 | +// | `readInt()` | `func() int` | 1行読み取り & 整数変換 | |
| 121 | +// | `readInts()` | `func() []int` | 複数整数を1行で読み取り | |
| 122 | + |
| 123 | +// --- |
| 124 | + |
| 125 | +// ## ✅ 計算量 |
| 126 | + |
| 127 | +// | 処理内容 | 時間計算量 | |
| 128 | +// | ------ | ------------ | |
| 129 | +// | グリッド構築 | O(N) | |
| 130 | +// | 累積和構築 | O(1500×1500) | |
| 131 | +// | クエリ処理 | O(Q) | |
| 132 | +// | **合計** | ≈ 数百万オーダー | |
| 133 | + |
| 134 | +// → **Go の処理性能なら 5 秒以内で十分対応可能** |
| 135 | + |
| 136 | +// ## ✅ メモリ消費量 |
| 137 | + |
| 138 | +// * `grid` + `prefix`: `1501×1501×4バイト×2 ≒ 約18MB` |
| 139 | +// * 制限(1024MiB)の **2%以下** に収まる。 |
| 140 | + |
| 141 | +// ## ✅ 補足 |
| 142 | + |
| 143 | +// * `bufio.Reader` を使って **高速な標準入力読み取り**。 |
| 144 | +// * `fmt.Fprintln(writer, ...)` により、**高速な出力**を実現。 |
| 145 | +// * 全体を **配列ベース(\[SIZE]\[SIZE]int)で確保済み**なので、メモリの再確保もなく非常に高速。 |
0 commit comments