[CodeForces] Moving Points
Posted lz87
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CodeForces] Moving Points相关的知识,希望对你有一定的参考价值。
Clarification:
The problem states that for each pair of points, we consider the minimum possible distance over any possible moments of time, including non-integer time interval. This means each different pair is independent, and we are only adding up each different pairs‘ possible minimum distance. This is different with taking a snap shot of a certain time, then add all pair distances at that time.
Analysis:
For a pair (Xj, Xi) such that Xj < Xi, if Vj <= Vi, D(Xj, Xi) is minimal at time 0, the distance will only increase over time; If Vj > Vi, then D(Xj, Xi) = 0, because Xj will eventually catch up will Xi. So we for each point Xi, its contribution as the bigger point initially toward the result distance sum only involves points Xj to its left with Vj <= Vi.
The naive approach takes O(N^2) time. Call the contribution of Xi as the bigger point S, S = (Xi - X1) + (Xi - X2) + ...... + (Xi - Xj), assuming X1 to Xj are all the points to Xi‘s left with a no greater speed. Denote Cnt as the number of such left points, S = Xi * Cnt - (X1 + X2 + ... + Xj) = Xi * Cnt - Sum(X1....Xj). The problem now is to get Cnt and Sum(X1, Xj).
To do this, we can use an dynamic data structure such as Binary Indexed Tree. The problem here is that both X and V can get as big as 10^8. A naive BIT implementation will consume too much memory. To avoid this, we apply a technique called coordinate compression on Speed V. This basically ranks all speed, since we only have up to O(10^5) different speeds, we are good with memory consumption.
Algorithm:
1. Compress all speeds to a relative ranking in range [1, N].
2. Combine points and their relative speed and sort on point position in ascending order.
3. Create two BIT cntBit and sumBit. cntBit is used to get the count of points to a given point‘s left, with a no greater speed. sumBit is used to get the sum of point positions to a given points‘ left, with a no greater speed.
4. Iterate all points from left to right, get cnt from cntBit and sum from sumBit, compute the current total sum, then update both BIT.
Because we process points in ascending order, it is guranteed that for each given point, we only consider points to its left. The coordinate compression ensures both BIT use relative speed ranking as their key. So a range sum query on cntBit using the given point P‘s ranking speed is equivalent to ask for the count of points that are located to the left of P with speed in [1, P‘s relative speed].
A range sum query on sumBit using P‘s ranking speed is to ask for the prefix sum of all such left points.
The running time of such algorithm is O(N*logN) with O(N) space complexity.
private static void solve(int q, FastScanner in, PrintWriter out) { for (int qq = 0; qq < q; qq++) { int n = in.nextInt(); int[] x = new int[n]; for(int i = 0; i < n; i++) { x[i] = in.nextInt(); } Integer[] v = new Integer[n]; for(int i = 0;i < n; i++) { v[i] = in.nextInt(); } v = ArrayUtils.compress(v); BinaryIndexedTree cntBit = new BinaryIndexedTree(n); BinaryIndexedTree sumBit = new BinaryIndexedTree(n); int[][] p = new int[n][2]; for(int i = 0; i < n; i++) { p[i][0] = x[i]; p[i][1] = v[i]; } Arrays.sort(p, Comparator.comparingInt(a -> a[0])); long sum = 0; for(int i = 0; i < n; i++) { long prevCnt = cntBit.rangeSum(p[i][1]); long prevSum = sumBit.rangeSum(p[i][1]); sum += (prevCnt * p[i][0] - prevSum); cntBit.adjust(p[i][1], 1); sumBit.adjust(p[i][1], p[i][0]); } out.println(sum); } out.close(); } private static class ArrayUtils { /* Compress all values of a to its rank in [1, a.length] */ private static Integer[] compress(Integer[] a) { int n = a.length; Integer[] ret = new Integer[n]; Integer[] copy = Arrays.copyOf(a, n); Arrays.sort(copy); int rank = 1; Map<Integer, Integer> map = new HashMap<>(); for(int v : copy) { if(!map.containsKey(v)) { map.put(v, rank); rank++; } } for(int i = 0; i < n; i++) { ret[i] = map.get(a[i]); } return ret; } } private static class BinaryIndexedTree { private long[] ft; private BinaryIndexedTree(int n) { ft = new long[n + 1]; } private long rangeSum(int l, int r) { return rangeSum(r) - (l == 1 ? 0 : rangeSum(l - 1)); } private long rangeSum(int r) { long sum = 0; for(; r > 0; r -= leastSignificantOne(r)) { sum += ft[r]; } return sum; } private void adjust(int k, int diff) { for(; k < ft.length; k += leastSignificantOne(k)) { ft[k] += diff; } } private int leastSignificantOne(int i) { return i & (-i); } }
以上是关于[CodeForces] Moving Points的主要内容,如果未能解决你的问题,请参考以下文章
@codeforces - 1209H@ Moving Walkways
ParticleSfM:Exploiting Dense Point Trajectories for Localizing Moving Cameras in the Wild——论文笔记
Codeforces Round #624 F. Moving Points 离散化 + 树状数组
A - Supercentral Point CodeForces - 165A