Skip to content

Commit

Permalink
Merge pull request yosupo06#1066 from maspypy/static_range_count_dist…
Browse files Browse the repository at this point in the history
…inct

問題追加 Static Range Count Distinct
  • Loading branch information
maspypy authored Dec 24, 2023
2 parents 04c23a7 + 7800f3e commit 1115a1b
Show file tree
Hide file tree
Showing 12 changed files with 434 additions and 0 deletions.
62 changes: 62 additions & 0 deletions datastructure/static_range_count_distinct/checker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// https://github.com/MikeMirzayanov/testlib/blob/master/checkers/wcmp.cpp

// The MIT License (MIT)

// Copyright (c) 2015 Mike Mirzayanov

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "testlib.h"

using namespace std;

int main(int argc, char * argv[])
{
setName("compare sequences of tokens");
registerTestlibCmd(argc, argv);

int n = 0;
string j, p;

while (!ans.seekEof() && !ouf.seekEof())
{
n++;

ans.readWordTo(j);
ouf.readWordTo(p);

if (j != p)
quitf(_wa, "%d%s words differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), compress(j).c_str(), compress(p).c_str());
}

if (ans.seekEof() && ouf.seekEof())
{
if (n == 1)
quitf(_ok, "\"%s\"", compress(j).c_str());
else
quitf(_ok, "%d tokens", n);
}
else
{
if (ans.seekEof())
quitf(_wa, "Participant output contains extra tokens");
else
quitf(_wa, "Unexpected EOF in the participants output");
}
}
43 changes: 43 additions & 0 deletions datastructure/static_range_count_distinct/gen/base.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <cassert>
#include <cstdio>
#include <set>
#include <vector>

#include "../params.h"
#include "random.h"

// |{a_i}| = sigma
void generate(Random &gen, const int N, const int Q, const int sigma) {
std::printf("%d %d\n", N, Q);

std::vector<int> S;
std::set<int> s;
for (int i = 0; i < sigma; i++) {
while (true) {
const int a = gen.uniform(A_MIN, A_MAX);
if (!s.count(a)) {
s.insert(a);
S.push_back(a);
break;
}
}
}

std::vector<int> a = S;
while (static_cast<int>(a.size()) < N) {
a.push_back(S[gen.uniform(0, sigma - 1)]);
}
gen.shuffle(a.begin(), a.end());

for (int i = 0; i < N; i++) {
if (i != 0) { std::printf(" "); }
std::printf("%d", a[i]);
}
std::printf("\n");

for (int i = 0; i < Q; i++) {
auto [l, r] = gen.uniform_pair(0, N + 1);
r -= 1;
std::printf("%d %d\n", l, r);
}
}
5 changes: 5 additions & 0 deletions datastructure/static_range_count_distinct/gen/example_00.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
5 3
3 7 1 2 1
1 5
3 3
0 4
33 changes: 33 additions & 0 deletions datastructure/static_range_count_distinct/gen/random.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <cmath>
#include <cstdlib>

#include "../params.h"
#include "base.hpp"
#include "random.h"

int main(int, char *argv[]) {
const long long seed = std::atoll(argv[1]);
Random gen(seed);

int N, Q;
if (seed < 3) {
N = gen.uniform<int>(100, N_MAX);
Q = gen.uniform<int>(100, Q_MAX);
} else {
N = N_MAX;
Q = Q_MAX;
}

int sigma;
if (seed % 3 == 0) {
sigma = 2;
} else if (seed % 3 == 1) {
sigma = std::sqrt(N);
} else {
sigma = N / 2;
}

generate(gen, N, Q, sigma);

return 0;
}
19 changes: 19 additions & 0 deletions datastructure/static_range_count_distinct/gen/small_n.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <cstdlib>

#include "../params.h"
#include "base.hpp"
#include "random.h"

int main(int, char *argv[]) {
const long long seed = std::atoll(argv[1]);
Random gen(seed);

const int N = N_MIN + seed;
if (N == 0) {
generate(gen, N, Q_MAX, 0);
} else {
generate(gen, N, Q_MAX, N);
}

return 0;
}
17 changes: 17 additions & 0 deletions datastructure/static_range_count_distinct/gen/small_q.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <cmath>
#include <cstdlib>

#include "../params.h"
#include "base.hpp"
#include "random.h"

int main(int, char *argv[]) {
const long long seed = std::atoll(argv[1]);
Random gen(seed);

const int Q = Q_MIN + seed;

generate(gen, N_MAX, Q, std::sqrt(N_MAX));

return 0;
}
24 changes: 24 additions & 0 deletions datastructure/static_range_count_distinct/hash.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"example_00.in": "cba296ed3f22fb90c8ca4f38f2a2ac27482150ceb9ca04bb53287f1be8f52e85",
"example_00.out": "45649e7d4f2c2652b02110d4cccd79b70d9b1d989de6edf2e32fec9de50b0201",
"random_00.in": "9b2d9aa52fda105d102bbbd1049c45f9acf769b46f47325155feda19351f47f6",
"random_00.out": "2aedf60d3c1d064636761b6567807808257b8d8e0ab6df0d91101e88fec2c3e8",
"random_01.in": "9cb5666ccab8cab22ec48504440406267d57747de32d045a8bc12dcc0254bd85",
"random_01.out": "c8243d087a037c9ce9d9f64bbacb0aaf337e9167136221bb3017e17c69679781",
"random_02.in": "8873d63b7c522dce5d2605dd31155b5d73e27b49ec71e2484e70c3187c216580",
"random_02.out": "2e165a8b374ccd9f9c443bc4abf2743303ed1e4538a196ad51e173b98245921d",
"random_03.in": "ae23db8b6de9c33f0c7d40b1d31f7336a92dab66f534500a4ef473886e743225",
"random_03.out": "f0ab6459a014b438578c3799109283a94d5714c9e842bd1574a8ea5debec06ee",
"random_04.in": "8641e7fe0d16d0b12603d754509d66f3cec1a1ceaf2e58130ca58ebb407986e6",
"random_04.out": "1a13440e0d060e276cc913fc7fddc2680c70eb819938c6c8aa3d850a7234e0ae",
"random_05.in": "133623752fe70fab0934e6187b23cf49cb5575e635a17aed09a0dd7fc80caa62",
"random_05.out": "a3d3595c05c01d747e9d6101653324bbdfc398563cb5483dc1f2ede295ee31e3",
"small_n_00.in": "64191b874ce3e5b40ea1965c3502c6f64014995e35a4cd8bd4f7416a87590371",
"small_n_00.out": "5a9061de234dcdec007b25ff8fd4a4491b247fcb33d79774fe9958339ef61947",
"small_n_01.in": "e1313aee9760e9592ae8668325d4962600537596257c4bb3a3d3ba9e1fb99943",
"small_n_01.out": "36f9d53b7ac18b7098b5a6bde13c37a345742661fea5e1fc13e46b0c44a901d3",
"small_n_02.in": "13cd7a039418a139672fba0c116bd1ee32d74867d0100da02a8ebcbfced4c185",
"small_n_02.out": "17b8cc89be5677b03d773c17abf389efd7453d949543ca17ea90fab48e709ab8",
"small_q_00.in": "1796a10a10f7a4352d8efc5315d9d720320fb9ee6911bedb8dd36e047b64fdd0",
"small_q_00.out": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
32 changes: 32 additions & 0 deletions datastructure/static_range_count_distinct/info.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
title = 'Static Range Count Distinct'
timelimit = 5.0
forum = "https://github.com/yosupo06/library-checker-problems/issues/770"

[[tests]]
name = "example.in"
number = 1

[[tests]]
name = "small_n.cpp"
number = 3

[[tests]]
name = "small_q.cpp"
number = 1

[[tests]]
name = "random.cpp"
number = 6

[[solutions]]
name = "naive.cpp"
wrong = false
allow_tle = true

[params]
N_MIN = 0
N_MAX = 500_000
Q_MIN = 0
Q_MAX = 500_000
A_MIN = 0
A_MAX = 1_000_000_000
116 changes: 116 additions & 0 deletions datastructure/static_range_count_distinct/sol/correct.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include <cstdio>
#include <vector>
#include <cassert>
#include <map>

using namespace std;

using ll = long long;

template <class T>
using vc = vector<T>;
template <class T>
using vvc = vector<vc<T>>;

#define FOR1(a) for (ll _ = 0; _ < ll(a); ++_)
#define FOR2(i, a) for (ll i = 0; i < ll(a); ++i)
#define FOR3(i, a, b) for (ll i = a; i < ll(b); ++i)
#define FOR4(i, a, b, c) for (ll i = a; i < ll(b); i += (c))
#define FOR1_R(a) for (ll i = (a)-1; i >= ll(0); --i)
#define FOR2_R(i, a) for (ll i = (a)-1; i >= ll(0); --i)
#define FOR3_R(i, a, b) for (ll i = (b)-1; i >= ll(a); --i)
#define overload4(a, b, c, d, e, ...) e
#define overload3(a, b, c, d, ...) d
#define FOR(...) overload4(__VA_ARGS__, FOR4, FOR3, FOR2, FOR1)(__VA_ARGS__)
#define FOR_R(...) overload3(__VA_ARGS__, FOR3_R, FOR2_R, FOR1_R)(__VA_ARGS__)

#define all(x) x.begin(), x.end()
#define len(x) ll(x.size())
#define elif else if

#define eb emplace_back

template <class Monoid>
struct SegTree {
using MX = Monoid;
using X = typename MX::value_type;
using value_type = X;
vc<X> dat;
int n, log, size;

SegTree() {}
SegTree(int n) { build(n); }

void build(int m) {
n = m, log = 1;
while ((1 << log) < n) ++log;
size = 1 << log;
dat.assign(size << 1, MX::unit());
}

void update(int i) { dat[i] = Monoid::op(dat[2 * i], dat[2 * i + 1]); }
void set(int i, const X &x) {
assert(i < n);
dat[i += size] = x;
while (i >>= 1) update(i);
}

X prod(int L, int R) {
assert(0 <= L && L <= R && R <= n);
X vl = Monoid::unit(), vr = Monoid::unit();
L += size, R += size;
while (L < R) {
if (L & 1) vl = Monoid::op(vl, dat[L++]);
if (R & 1) vr = Monoid::op(dat[--R], vr);
L >>= 1, R >>= 1;
}
return Monoid::op(vl, vr);
}
};

template <typename X>
struct Monoid_Add {
using value_type = X;
static constexpr X op(const X &x, const X &y) noexcept { return x + y; }
static constexpr X inverse(const X &x) noexcept { return -x; }
static constexpr X power(const X &x, ll n) noexcept { return X(n) * x; }
static constexpr X unit() { return X(0); }
static constexpr bool commute = true;
};

int main() {
int N, Q;
scanf("%d%d", &N, &Q);

vector<int> A(N);
FOR(i, N) scanf("%d", &A[i]);

vc<int> ANS(Q);

// r -> q, l
vvc<pair<int, int>> query(N);
FOR(q, Q) {
int l, r;
scanf("%d%d", &l, &r);
if (l == r) continue;
query[r - 1].eb(q, l);
}

SegTree<Monoid_Add<int>> seg(N);
map<int, int> MP;
FOR(r, N) {
int x = A[r];
int p = MP.count(x) ? MP[x] : -1;
if (p != -1) seg.set(p, 0);
seg.set(r, 1);
MP[x] = r;
for (auto x: query[r]) {
int q = x.first, l = x.second;
ANS[q] = seg.prod(l, r + 1);
}
}

for (int q = 0; q < Q; ++q) printf("%d\n", ANS[q]);

return 0;
}
22 changes: 22 additions & 0 deletions datastructure/static_range_count_distinct/sol/naive.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <algorithm>
#include <cstdio>
#include <vector>
#include <set>

using namespace std;

int main() {
int N, Q;
scanf("%d%d", &N, &Q);
vector<int> A(N);
for (int i = 0; i < N; i++) { scanf("%d", &A[i]); }

for (int i = 0; i < Q; i++) {
int l, r;
scanf("%d%d", &l, &r);
set<int> S = {A.begin() + l, A.begin() + r};
int ans = S.size();
printf("%d\n", ans);
}
return 0;
}
Loading

0 comments on commit 1115a1b

Please sign in to comment.