結果
問題 |
No.3116 More and more teleporter
|
ユーザー |
![]() |
提出日時 | 2025-04-18 21:38:55 |
言語 | Java (openjdk 23) |
結果 |
AC
|
実行時間 | 1,286 ms / 2,000 ms |
コード長 | 10,072 bytes |
コンパイル時間 | 4,987 ms |
コンパイル使用メモリ | 101,692 KB |
実行使用メモリ | 105,764 KB |
最終ジャッジ日時 | 2025-04-18 21:39:21 |
合計ジャッジ時間 | 21,028 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 22 |
ソースコード
import java.io.*; import java.util.Arrays; import java.util.function.*; public class Main { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] sa = br.readLine().split(" "); int n = Integer.parseInt(sa[0]); int q = Integer.parseInt(sa[1]); LazySegTree<Integer, Integer> stL = new LazySegTree<>( n + 1, 1, (s1, s2) -> { return Math.max(s1, s2); }, (f, s) -> { return Math.max(f, s); }, (f1, f2) -> { return Math.max(f1, f2); }, 1); LazySegTree<Integer, Integer> stR = new LazySegTree<>( n + 1, n * 2, (s1, s2) -> { return Math.min(s1, s2); }, (f, s) -> { return Math.min(f, s); }, (f1, f2) -> { return Math.min(f1, f2); }, n * 2); PrintWriter pw = new PrintWriter(System.out); for (int i = 0; i < q; i++) { sa = br.readLine().split(" "); int t = Integer.parseInt(sa[0]); int x = Integer.parseInt(sa[1]); if (t == 1) { int ans = x - 1; ans = Math.min(ans, x - stL.get(x)); ans = Math.min(ans, stR.get(x) - x); pw.println(ans); } else { int c = Integer.parseInt(sa[2]); stL.apply(x, n + 1, x - c); stR.apply(1, x + 1, x + c); } } pw.flush(); br.close(); } } class LazySegTree<S, F> { private final int n; // 要素数 private final int size; // 葉の数(n以上の最小の2べき) private final int log; // 2^log = size private final BinaryOperator<S> op; // 二項演算 private final S e; // 単位元 private final BiFunction<F, S, S> mapping; // f(x) private final BinaryOperator<F> composition; // 合成関数 private final F id; // 恒等写像 private final S[] data; private final F[] lazy; /** * 長さnの配列aを作る。初期値は全て単位元。<br> * O(n)<br> * S:モノイドの型<br> * F:写像の型 * * @param n 要素数 * @param e 単位元 * @param op 二項演算 * @param mapping f(x)を返す関数 * @param composition fとgの合成関数 * @param id 恒等写像 */ @SuppressWarnings("unchecked") public LazySegTree(int n, S e, BinaryOperator<S> op, BiFunction<F, S, S> mapping, BinaryOperator<F> composition, F id) { this.n = n; int k = 1; while (k < n) k <<= 1; this.size = k; this.log = Integer.numberOfTrailingZeros(size); this.op = op; this.e = e; this.mapping = mapping; this.composition = composition; this.id = id; this.data = (S[]) new Object[size << 1]; this.lazy = (F[]) new Object[size]; Arrays.fill(data, e); Arrays.fill(lazy, id); } /** * 長さdat.lengthの配列aをdatを元に作る。<br> * O(n)<br> * S:モノイドの型<br> * F:写像の型 * * @param dat 初期データ * @param e 単位元 * @param op 二項演算 * @param mapping f(x)を返す関数 * @param composition fとgの合成関数 * @param id 恒等写像 */ public LazySegTree(S[] dat, S e, BinaryOperator<S> op, BiFunction<F, S, S> mapping, BinaryOperator<F> composition, F id) { this(dat.length, e, op, mapping, composition, id); build(dat); } private void build(S[] dat) { int l = dat.length; System.arraycopy(dat, 0, data, size, l); for (int i = size - 1; i > 0; i--) { data[i] = op.apply(data[i << 1 | 0], data[i << 1 | 1]); } } /** * a[p] = xとする。<br> * O(log n) * * @param p 設定位置(0≦p<n) * @param x 設定値 */ void set(int p, S x) { assert 0 <= p && p < n : "p=" + p; p += size; pushTo(p); data[p] = x; updateFrom(p); } /** * a[p]を取得する。<br> * O(log n) * * @param p 取得位置(0≦p<n) */ S get(int p) { assert 0 <= p && p < n : "p=" + p; p += size; pushTo(p); return data[p]; } /** * 区間l~(r-1)の計算を行う。<br> * l=rのときは単位元を返す。<br> * O(log n) * * @param l 開始位置(含む) (0≦l≦r≦n) * @param r 終了位置(含まない)(0≦l≦r≦n) */ S prod(int l, int r) { assert 0 <= l && l <= r && r <= n : "l=" + l + ", r=" + r; if (l == r) return e; l += size; r += size; pushTo(l, r); S sumLeft = e, sumRight = e; while (l < r) { if ((l & 1) == 1) sumLeft = op.apply(sumLeft, data[l++]); if ((r & 1) == 1) sumRight = op.apply(data[--r], sumRight); l >>= 1; r >>= 1; } return op.apply(sumLeft, sumRight); } /** * 全区間の計算を行う。<br> * O(1) */ S allProd() { return data[1]; } /** * a[p]に作用素fを作用させる。<br> * O(log n) * * @param p 取得位置(0≦p<n) * @param f 作用素 */ void apply(int p, F f) { assert 0 <= p && p < n : "p=" + p; p += size; pushTo(p); data[p] = mapping.apply(f, data[p]); updateFrom(p); } /** * a[l]~a[r-1]に作用素fを作用させる。<br> * O(log n) * * @param l 開始位置(含む) (0≦l≦r≦n) * @param r 終了位置(含まない)(0≦l≦r≦n) * @param f 作用素 */ void apply(int l, int r, F f) { assert 0 <= l && l <= r && r <= n : "l=" + l + ", r=" + r; if (l == r) return; l += size; r += size; pushTo(l, r); for (int l2 = l, r2 = r; l2 < r2;) { if ((l2 & 1) == 1) { data[l2] = mapping.apply(f, data[l2]); if (l2 < size) lazy[l2] = composition.apply(f, lazy[l2]); l2++; } if ((r2 & 1) == 1) { r2--; data[r2] = mapping.apply(f, data[r2]); if (r2 < size) lazy[r2] = composition.apply(f, lazy[r2]); } l2 >>= 1; r2 >>= 1; } updateFrom(l, r); } /** * f(op(l~(r-1)))=trueとなる最大のrを返す。<br> * (計算区間にrを追加するとfalseになる)<br> * O(log n) * * @param l 左端(含む)(0≦l≦n) * @param f 判定関数(f(e)=true) * @return 条件を満たす最大のr */ int maxRight(int l, Predicate<S> f) { assert 0 <= l && l <= n : "l=" + l; assert f.test(e); if (l == n) return n; l += size; pushTo(l); S sum = e; do { l >>= Integer.numberOfTrailingZeros(l); if (!f.test(op.apply(sum, data[l]))) { while (l < size) { push(l); l = l << 1; if (f.test(op.apply(sum, data[l]))) { sum = op.apply(sum, data[l]); l++; } } return l - size; } sum = op.apply(sum, data[l]); l++; } while ((l & -l) != l); return n; } /** * f(op(l~(r-1)))=trueとなる最小のlを返す。<br> * (計算区間に(l-1)を追加するとfalseになる)<br> * O(log n) * * @param r 右端(含まない)(0≦r≦n) * @param f 判定関数(f(e)=true) * @return 条件を満たす最小のl */ int minLeft(int r, Predicate<S> f) { assert 0 <= r && r <= n : "r=" + r; assert f.test(e); if (r == 0) return 0; r += size; pushTo(r - 1); S sum = e; do { r--; while (r > 1 && (r & 1) == 1) r >>= 1; if (!f.test(op.apply(data[r], sum))) { while (r < size) { push(r); r = r << 1 | 1; if (f.test(op.apply(data[r], sum))) { sum = op.apply(data[r], sum); r--; } } return r + 1 - size; } sum = op.apply(data[r], sum); } while ((r & -r) != r); return 0; } private void pushTo(int k) { for (int i = log; i > 0; i--) push(k >> i); } private void pushTo(int lk, int rk) { for (int i = log; i > 0; i--) { if (((lk >> i) << i) != lk) push(lk >> i); if (((rk >> i) << i) != rk) push(rk >> i); } } private void push(int k) { if (lazy[k] == id) return; int lk = k << 1 | 0, rk = k << 1 | 1; data[lk] = mapping.apply(lazy[k], data[lk]); data[rk] = mapping.apply(lazy[k], data[rk]); if (lk < size) lazy[lk] = composition.apply(lazy[k], lazy[lk]); if (rk < size) lazy[rk] = composition.apply(lazy[k], lazy[rk]); lazy[k] = id; } private void updateFrom(int k) { k >>= 1; while (k > 0) { data[k] = op.apply(data[k << 1 | 0], data[k << 1 | 1]); k >>= 1; } } private void updateFrom(int lk, int rk) { for (int i = 1; i <= log; i++) { if (((lk >> i) << i) != lk) { int lki = lk >> i; data[lki] = op.apply(data[lki << 1 | 0], data[lki << 1 | 1]); } if (((rk >> i) << i) != rk) { int rki = (rk - 1) >> i; data[rki] = op.apply(data[rki << 1 | 0], data[rki << 1 | 1]); } } } // **************** DEBUG **************** // private int indent = 6; void setIndent(int newIndent) { this.indent = newIndent; } @Override public String toString() { return toDetailedString(); } /** * セグメント木全体の要素をツリー状に出力。 */ String toDetailedString() { return toDetailedString(1, 0, simulatePushAll()); } private String toDetailedString(int k, int sp, S[] dat) { if (k >= size) return indent(sp) + dat[k]; StringBuilder sb = new StringBuilder(); sb.append(toDetailedString(k << 1 | 1, sp + indent, dat)); sb.append("\n"); sb.append(indent(sp) + dat[k]); sb.append("\n"); sb.append(toDetailedString(k << 1 | 0, sp + indent, dat)); return sb.toString(); } private static String indent(int n) { StringBuilder sb = new StringBuilder(); while (n-- > 0) sb.append(' '); return sb.toString(); } /** * n件の要素のみを、配列形式で出力。 */ String toSimpleString() { S[] dat = simulatePushAll(); StringBuilder sb = new StringBuilder(); sb.append('['); for (int i = 0; i < size; i++) { sb.append(dat[i + size]); if (i < size - 1) sb.append(',').append(' '); } sb.append(']'); return sb.toString(); } private S[] simulatePushAll() { S[] simDat = Arrays.copyOf(data, 2 * size); F[] simLaz = Arrays.copyOf(lazy, 2 * size); for (int k = 1; k < size; k++) { if (simLaz[k] == id) continue; int lk = k << 1 | 0, rk = k << 1 | 1; simDat[lk] = mapping.apply(simLaz[k], simDat[lk]); simDat[rk] = mapping.apply(simLaz[k], simDat[rk]); if (lk < size) simLaz[lk] = composition.apply(simLaz[k], simLaz[lk]); if (rk < size) simLaz[rk] = composition.apply(simLaz[k], simLaz[rk]); simLaz[k] = id; } return simDat; } }