タイトル効果:{<A、B>}設定された接続のタプル、トリプルB {<C、D、E>}のセットが与えられると、Cは上にAとB {B = E}のように定義されますポイントの最高値の数:、すなわち、Cを求めているバンプの数を設定します。
解釈:
Cは、問題が次元の半順序の問題は直接重複排除後に計算することができ、バンプの数に相当し求めて、トリプルのセットです。
しかし、直接暴力的な操作に接続することが判明した場合、最悪の場合があります\(O(NM)\) C-タプル、空間と時間は余裕がありません。値への唯一の最大の貢献すべてのタプルの同じb値のための発見は、それが答えを持っていることがあります。したがって、各Bについて考えると、我々は最大とタプルの対応する数を発見しました。したがって、Bの各タプルのために最も対応するタプル、すなわちのうちの1つにすぎない。せいぜいC法的要素\(O(M)\) A、答えはM結合しています。
この問題はCでは、Dレンジしたがって、ツリー次元アレイは、直接、すなわち、メンテナンスのために使用することができ、小さい:ソート、およびメンテナンスC、Dは、ツリー・アレイを使用することができます。
注:3つの部分の順序が問題に重みを行かなければなりません。
コードは以下の通りです
#include <bits/stdc++.h>
using namespace std;
struct A {
int a, b;
};
struct B {
int c, d, e;
};
struct C {
int a, c, d, cnt;
C(int x, int y, int z, int w) {
a = x, c = y, d = z, cnt = w;
}
friend bool operator==(const C &x, const C &y) {
return x.a == y.a && x.c == y.c && x.d == y.d;
}
};
struct fenwick {
vector<vector<int>> t;
int n;
fenwick(int _n) {
n = _n;
t.resize(_n + 1, vector<int>(_n + 1));
}
void modify(int x, int y, int val) {
for (int i = x; i <= n; i += i & -i) {
for (int j = y; j <= n; j += j & -j) {
t[i][j] += val;
}
}
}
int query(int x, int y) {
int ret = 0;
for (int i = x; i; i -= i & -i) {
for (int j = y; j; j -= j & -j) {
ret += t[i][j];
}
}
return ret;
}
int get(int x, int y) {
return query(n, n) - query(n, y - 1) - query(x - 1, n) + query(x - 1, y - 1);
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T, kase = 0;
cin >> T;
while (T--) {
int n, m, range = 0, fen_size = 0;
cin >> n >> m;
vector<A> a(n); // a, b
vector<B> b(m); // c, d, e
for (int i = 0; i < n; i++) {
cin >> a[i].a >> a[i].b;
range = max(range, a[i].b);
}
for (int i = 0; i < m; i++) {
cin >> b[i].c >> b[i].d >> b[i].e;
range = max(range, b[i].e);
fen_size = max(fen_size, max(b[i].c, b[i].d));
}
vector<pair<int, int>> maxa(range + 1); // maxa, cnt
for (int i = 0; i < n; i++) {
if (a[i].a > maxa[a[i].b].first) {
maxa[a[i].b].first = a[i].a;
maxa[a[i].b].second = 1;
} else if (a[i].a == maxa[a[i].b].first) {
maxa[a[i].b].second++;
}
}
vector<C> all, valid;
for (int i = 0; i < m; i++) {
if (maxa[b[i].e].second != 0) {
all.emplace_back(maxa[b[i].e].first, b[i].c, b[i].d, maxa[b[i].e].second);
}
}
sort(all.begin(), all.end(), [&](const C &x, const C &y) {
return x.a == y.a ? x.c == y.c ? x.d > y.d : x.c > y.c : x.a > y.a;
});
valid.emplace_back(all.front());
for (int i = 1; i < (int)all.size(); i++) {
if (all[i] == valid.back()) {
valid.back().cnt += all[i].cnt;
} else {
valid.emplace_back(all[i]);
}
}
int ans = 0;
fenwick t(fen_size);
for (int i = 0; i < (int)valid.size(); i++) {
if (t.get(valid[i].c, valid[i].d) == 0) {
ans += valid[i].cnt;
}
t.modify(valid[i].c, valid[i].d, 1);
}
cout << "Case #" << ++kase << ": " << ans << endl;
}
return 0;
}