ARC 035D: 高橋くんとマラソンコース (セグメント木)

解法

チェックポイント間の経路数はものすごく大きくなるのでlogで保存しておく。クエリに対してチェックポイント間の経路数の和を返すので、和のセグメント木を作っておく。

コード

import java.io.IOException;

public class Main {
	private static double[] segtree;
	private static int[][] cP;
	private static int MAX_N;

	public static void main(String[] args) {
		int N = nextInt();
		cP = new int[N][2];
		for (int i = 0; i < cP.length; i++) {
			cP[i][0] = nextInt();
			cP[i][1] = nextInt();
		}

		// チェックポイントnからチェックポイントn+1へ行く時の経路の組み合わせをpatterns[n]に入れておく
		// logで入れておく
		MAX_N = 1;
		while (N > MAX_N) {
			MAX_N *= 2;
		}
		segtree = new double[2 * MAX_N - 1];
		for (int i = 0; i < N - 1; i++) {
			combi(i);
		}

		int Q = nextInt();
		for (int i = 0; i < Q; i++) {
			int t = nextInt();
			if (t == 1) {
				int k = nextInt() - 1;
				cP[k][0] = nextInt();
				cP[k][1] = nextInt();
				if (k > 0) {
					combi(k - 1);
				}
				if (k < N - 1) {
					combi(k);
				}
			} else {
				int l1 = nextInt() - 1;
				int r1 = nextInt() - 1;
				double first = querySegTree(l1, r1);

				int l2 = nextInt() - 1;
				int r2 = nextInt() - 1;
				double second = querySegTree(l2, r2);
				if (first > second) {
					System.out.println("FIRST");
				} else {
					System.out.println("SECOND");
				}
			}
		}
	}

	static void updateSegTree(int k, double a) {
		k += MAX_N - 1;
		segtree[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			segtree[k] = segtree[k * 2 + 1] + segtree[k * 2 + 2];
		}
	}

	static double querySegTree(int a, int b) {
		return querySegTree(a, b, 0, 0, MAX_N);
	}

	static double querySegTree(int a, int b, int k, int l, int r) {
		if (r <= a || b <= l) {
			return 0;
		}
		if (a <= l && r <= b) {
			return segtree[k];
		}
		int m = (l + r) / 2;
		return (querySegTree(a, b, 2 * k + 1, l, m) + querySegTree(a, b, 2 * k + 2, m, r));
	}

	static void combi(int n) {
		// チェックポイントnからチェックポイントn+1へ行く時の経路の組み合わせをpatterns[n]に入れておく
		int x = Math.abs(cP[n][0] - cP[n + 1][0]);
		int y = Math.abs(cP[n][1] - cP[n + 1][1]);
		int min = Math.min(x, y);
		int max = x + y;
		// maxCminをもとめる
		double p = 0;
		for (int j = max; j > max - min; j--) {
			p += Math.log(j);
		}
		for (int j = 2; j <= min; j++) {
			p -= Math.log(j);
		}
		updateSegTree(n, p);
	}

	static int nextInt() {
		int c;
		try {
			c = System.in.read();
			while (c != '-' && (c < '0' || c > '9'))
				c = System.in.read();
			if (c == '-')
				return -nextInt();
			int res = 0;
			while (c >= '0' && c <= '9') {
				res = res * 10 + c - '0';
				c = System.in.read();
			}
			return res;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return -1;
	}
}