Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python Sol 1063 content/3_Silver/Sorting_Custom.mdx #4899

Merged
merged 8 commits into from
Nov 5, 2024
193 changes: 99 additions & 94 deletions content/3_Silver/Sorting_Custom.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -619,11 +619,9 @@ edges.sort(key=lambda edge: (edge.w, edge.a))
Sorting by an arbitrary number of criteria is done similarly.

<LanguageSection>

<CPPSection>

</CPPSection>

<JavaSection>

With Java, we can implement a comparator for arrays of arbitrary length
Expand Down Expand Up @@ -663,7 +661,6 @@ public class Sol {
```

</JavaSection>

<PySection>

</PySection>
Expand Down Expand Up @@ -705,65 +702,63 @@ compression at the beginning. Observe how a custom comparator is used to sort
the points:

<LanguageSection>

<CPPSection>

```cpp
// BeginCodeSnip{Solution code}
#include <algorithm>
#include <iostream>

using namespace std;
// EndCodeSnip

typedef pair<int, int> Point;
bool ycomp(Point p, Point q) { return p.second < q.second; }

// BeginCodeSnip{Solution code}
const int MAX_N = 2500;
int N, Psum[MAX_N + 1][MAX_N + 1];
Point P[MAX_N];
int pref[MAX_N + 1][MAX_N + 1];
Point p[MAX_N];

int rsum(int x1, int y1, int x2, int y2) {
return Psum[x2 + 1][y2 + 1] - Psum[x2 + 1][y1] - Psum[x1][y2 + 1] + Psum[x1][y1];
return pref[x2 + 1][y2 + 1] - pref[x2 + 1][y1] - pref[x1][y2 + 1] + pref[x1][y1];
}

int main(void) {
cin >> N;
for (int i = 0; i < N; i++) {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
P[i] = make_pair(x, y);
p[i] = make_pair(x, y);
}

sort(p, p + n);
for (int i = 0; i < n; i++) { p[i].first = i + 1; }
sort(p, p + n, ycomp);
for (int i = 0; i < n; i++) { p[i].second = i + 1; }

for (int i = 0; i < n; i++) { pref[p[i].first][p[i].second] = 1; }
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
pref[i][j] += pref[i - 1][j] + pref[i][j - 1] - pref[i - 1][j - 1];
}
}
// EndCodeSnip

sort(P, P + N);
for (int i = 0; i < N; i++) P[i].first = i + 1;
sort(P, P + N, ycomp);
for (int i = 0; i < N; i++) P[i].second = i + 1;

// BeginCodeSnip{Solution code}
for (int i = 0; i < N; i++) Psum[P[i].first][P[i].second] = 1;
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
Psum[i][j] += Psum[i - 1][j] + Psum[i][j - 1] - Psum[i - 1][j - 1];
long long answer = 0;
for (int i = 0; i < N; i++)
for (int j = i; j < N; j++) {
int x1 = min(P[i].first, P[j].first) - 1;
int x2 = max(P[i].first, P[j].first) - 1;
answer += rsum(0, i, x1, j) * rsum(x2, i, N - 1, j);
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
int x1 = min(p[i].first, p[j].first) - 1;
int x2 = max(p[i].first, p[j].first) - 1;
answer += rsum(0, i, x1, j) * rsum(x2, i, n - 1, j);
}
cout << answer + 1 << "\n";
}

cout << answer + 1 << endl;
}
// EndCodeSnip
```

</CPPSection>

<JavaSection>

```java
// BeginCodeSnip{Solution code}
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
Expand All @@ -779,7 +774,6 @@ public class RectangularPasture {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
// EndCodeSnip

int[] xs = new int[n];
int[] ys = new int[n];
Expand All @@ -796,7 +790,6 @@ public class RectangularPasture {
Arrays.sort(cows, Comparator.comparingInt(j -> ys[j]));
for (int y = 1; y <= n; y++) { ys[cows[y - 1]] = y; }

// BeginCodeSnip{Solution code}
sums = new int[n + 1][n + 1];
for (int j = 0; j < n; j++) { sums[xs[j]][ys[j]]++; }
for (int x = 0; x <= n; x++) {
Expand All @@ -806,6 +799,7 @@ public class RectangularPasture {
if (x > 0 && y > 0) { sums[x][y] -= sums[x - 1][y - 1]; }
}
}

long answer = n + 1;
for (int j = 0; j < n; j++) {
for (int k = j + 1; k < n; k++) {
Expand All @@ -815,19 +809,62 @@ public class RectangularPasture {
Math.max(ys[j], ys[k]), n);
}
}

System.out.println(answer);
}
}
// EndCodeSnip
```

The solution uses a
[lambda](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)
function as the custom comparator, which our guide didn't discuss, but it should
be apparent which coordinate (`x` or `y`) that the comparator is sorting by.

</JavaSection>
<PySection>

<Warning>

Due to Python's constant factor, the below code will TLE
on a couple test cases despite having the correct time complexity.

</Warning>

```py
import sys

input = sys.stdin.readline

n = int(input().strip())
points = [list(map(int, input().strip().split())) for _ in range(n)]

points.sort(key=lambda i: i[1])
for i in range(n):
points[i][1] = i + 1

points.sort(key=lambda i: i[0])
for i in range(n):
points[i][0] = i + 1

psa = [[0 for _ in range(n + 1)] for _ in range(n + 1)]
for x, y in points:
psa[x][y] = 1

for x in range(1, n + 1):
for y in range(1, n + 1):
psa[x][y] += psa[x - 1][y] + psa[x][y - 1] - psa[x - 1][y - 1]

ans = n + 1

for s in range(n):
for e in range(s + 1, n):
srt, end = points[s][0], points[e][0]
top = max(points[s][1], points[e][1])
bottom = min(points[s][1], points[e][1])

above = psa[end][n] - psa[srt - 1][n] - psa[end][top] + psa[srt - 1][top]
below = psa[end][bottom - 1] - psa[srt - 1][bottom - 1]
ans += (above + 1) * (below + 1)

print(ans)
```

</PySection>
</LanguageSection>

The solution to Rectangular Pasture directly replaces coordinates with their
Expand Down Expand Up @@ -858,12 +895,10 @@ We also provide a more detailed explanation:

First of all, let's figure out the value at each index in array $a$. It would be
too slow to loop through every index in every update interval as well as every
index in a query interval
(The complexity would be $O(C(N+Q))$,
where $C$ is the maximum coordinate given in the input).
At the same time, that approach would take $O(C)$ memory, which is also too much.
Instead, we make an observation
that will make prefix sums paired with coordinate compression a viable option.
index in a query interval (The complexity would be $O(C(N+Q))$, where $C$ is the
maximum coordinate given in the input). At the same time, that approach would
take $O(C)$ memory, which is also too much. Instead, we make an observation that
will make prefix sums paired with coordinate compression a viable option.

Not every index in the whole range from $1...10^9$ is used in updates. In fact,
there can be large intervals of indices that all have the same value. Call every
Expand Down Expand Up @@ -920,11 +955,9 @@ answer these range sum queries in O(1) each.
</Spoiler>

<LanguageSection>

<CPPSection>

```cpp
// BeginCodeSnip{Solution code}
#include <bits/stdc++.h>

using namespace std;
Expand All @@ -949,18 +982,13 @@ pair<pair<int, int>, int> updates[100005]; // updates in given in the input <<l

// EndCodeSnip

// finds the "compressed index" of a special index (a.k.a. its position in the
// sorted list)
/** @return the compressed index of a special index (it), aka its index in the
* compressed list */
int getCompressedIndex(int a) {
return lower_bound(indices.begin(), indices.end(), a) - indices.begin();
}

// BeginCodeSnip{Solution code}

int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);

int N, Q;
cin >> N >> Q;

Expand All @@ -978,20 +1006,11 @@ int main() {
indices.push_back(r);
queries[i] = {l, r};
}
// EndCodeSnip
//========= COORDINATE COMPRESSION =======

// Perform coordinate compression by sorting and removing duplicates
sort(indices.begin(), indices.end());
indices.erase(unique(indices.begin(), indices.end()), indices.end());
/*
You can find info on "unique" here:
https://www.cplusplus.com/reference/algorithm/unique/

Since our list is already sorted, the effect of "unique" is duplicates are
removed. In total, these two lines give us a sorted list with duplicates
removed.
*/
//========= COORDINATE COMPRESSION =======
// BeginCodeSnip{Solution code}

// We create the difference array, using coordinate compression and binary
// search to get the compressed index of each special index Note the 1-based
// indexing for convenience
Expand Down Expand Up @@ -1026,27 +1045,20 @@ int main() {
prefix_sums[getCompressedIndex(queries[i].first)]
<< "\n";
}

return 0;
}
// EndCodeSnip
```

</CPPSection>

<JavaSection>

```java
// BeginCodeSnip{Solution code}
import java.io.*;
import java.util.*;

public class rangequeries {

public class StaticRangeQueries {
// custom class that stores a few integers (used for directly storing the
// queries and updates given in the input)
static class Query {

int l, r, v;
public Query(int l, int r, int v) {
this.l = l;
Expand Down Expand Up @@ -1074,16 +1086,17 @@ public class rangequeries {
static ArrayList<Integer> indices; // sorted list of special indices
static Query queries[]; // queries given in the input <l, r>
static Query updates[]; // updates in given in the input <l, r, v>
// EndCodeSnip
// finds the "compressed index" of a special index (a.k.a. its position in
// the sorted list)

/**
* @return the compressed index of a special index (it), aka its index in the
* compressed list
*/
static int getCompressedIndex(int a) {
return Collections.binarySearch(indices, a);
}
// BeginCodeSnip{Solution code}

public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(
System.in)); // A Scanner is too slow to solve this problem!
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken()), Q = Integer.parseInt(st.nextToken());
Expand All @@ -1109,18 +1122,12 @@ public class rangequeries {
indices.add(r);
queries[i] = new Query(l, r);
}
// EndCodeSnip
//========= COORDINATE COMPRESSION =======

// Coordinate compress by adding the indices to a sorted set and vice versa
TreeSet<Integer> temp = new TreeSet<Integer>(indices);
// Since temp is a set, all duplicate elements are removed
indices.clear();
indices.addAll(temp); // The elements of temp will be added to indices
// in sorted order, since temp is a TreeSet
// The effect of these lines is to sort indices while removing duplicate
// elements. While this is not the only way to do it, it is one that
// requires little code.
//========= COORDINATE COMPRESSION =======
// BeginCodeSnip{Solution code}
indices.addAll(temp);

difference_array = new long[indices.size() + 5];
widths = new int[indices.size() + 5];
interval_value = new long[indices.size() + 5];
Expand Down Expand Up @@ -1161,11 +1168,9 @@ public class rangequeries {
}
}
}
// EndCodeSnip
```

</JavaSection>

</LanguageSection>

## Problems
Expand Down
Loading