GYM102596L Yosupo's Algorithm【分治,支配对】
给定平面上 \(2n\) 个点,每个点有坐标 \((x_i,y_i)\),权值 \(w_i\) 及颜色 \(c_i\)。
所有点满足:若 \(c_i=0\),则 \(x_i <0\);若 \(c_i=1\),则 \(x_i > 0\)。
\(q\) 次查询,每次给定 \(L_i,R_i\),你需要选择两个点 \(i,j\) 满足如下条件:
- \(c_i= 0,c_j=1\)。
- \(x_i < L,x_j > R\) 或 \(x_i > L,x_j < R\)。
- \(y_i < y_j\)。
求 \(w_i + w_j\) 的最大值。
\(1 \le n \le 10^5\),\(1 \le q \le 5 \times 10^5\),\(x_i,L_i,R_i\) 互不相同,\(y_i\) 互不相同。
注意到查询只关于 \(x\),感觉 \(x\) 和 \(y\) 两维好像相对独立,我们考虑先处理 \(y\) 的限制找到所有可能对答案有贡献的点对,那么查询就只需要扫描线树状数组。
直接枚举,点对的数量会达到 \(\mathcal{O}(n^2)\) 级别,不可接受。考虑对 \(y\) 分治,注意到对于当前层,分类讨论一下可以发现,最优的点对一定包含两种颜色的点的最大 \(w_i\) 中的至少一个,因此我们可以只考虑总共 \(\mathcal{O}(n\log n)\) 个点对。这样总时间复杂度就是 \(\mathcal{O}(n \log^2 n + q\log n)\) 的了。
code
#include <bits/stdc++.h>
#define all(x) x.begin(), x.end()
typedef long long LL;
using namespace std;
constexpr int N = 1e6 + 5;
void chkmx(int &x, int y) {
x = x > y ? x : y;
}
struct info {
int x, y, v, c;
bool operator < (const info &p) const {
return y < p.y;
}
} p[N * 2];
struct qu {
int l, r, v;
bool operator < (const qu &p) const {
return l < p.l;
}
} f[N], g[N];
int n, q, m, cp, ans[N];
vector <qu> ad;
struct BIT1 { // prefix max
int c[N << 2];
void mdf(int x, int v) {
for (int i = x; i <= m; i += i & -i) chkmx(c[i], v);
}
int qry(int x) {
int res = 0;
for (int i = x; i; i -= i & -i) chkmx(res, c[i]);
return res;
}
} bit1;
struct BIT2 { // suffix max
int c[N << 2];
void mdf(int x, int v) {
// cerr << "mdf " << x << " " << v << "\n";
for (int i = x; i; i -= i & -i) chkmx(c[i], v);
}
int qry(int x) {
int res = 0;
for (int i = x; i <= m; i += i & -i) chkmx(res, c[i]);
return res;
}
} bit2;
void solve(int l, int r) {
if (l == r) return;
vector <info> tp, tq;
int mid = l + r >> 1;
// cerr << "[" << l << ", " << mid << "], [" << mid + 1 << ", " << r << "]\n";
for (int i = l; i <= mid; i++) {
if (p[i].c == 0) tp.emplace_back(p[i]);
}
for (int i = mid + 1; i <= r; i++) {
if (p[i].c == 1) tq.emplace_back(p[i]);
}
if (tp.empty() || tq.empty()) goto skip;
sort(all(tp), [&](info x, info y) {
return x.x > y.x;
});
sort(all(tq), [&](info x, info y) {
return x.x < y.x;
});
// cerr << "[" << l << ", " << r << "]\n";
// for (auto it : tp) cerr << it.x << " " << it.y << " p\n";
// for (auto it : tq) cerr << it.x << " " << it.y << " q\n";
// vector <info> tmp;
// for (auto it : tp) {
// if (tmp.empty()) tmp.emplace_back(it);
// else {
// if (it.v >= tmp.back().v)
// tmp.emplace_back(it);
// }
// }
// swap(tmp, tp);
// tmp.clear();
// for (auto it : tq) {
// if (tmp.empty()) tmp.emplace_back(it);
// else {
// if (it.v >= tmp.back().v)
// tmp.emplace_back(it);
// }
// }
// swap(tmp, tq);
// tmp.clear();
// auto np = tp.back();
// auto nq = tq.back();
info np, nq;
np.v = 0;
nq.v = 0;
for (auto it : tp) if (it.v >= np.v) np = it;
for (auto it : tq) if (it.v >= nq.v) nq = it;
for (auto it : tq) {
ad.emplace_back((qu){np.x, it.x, np.v + it.v});
}
for (auto it : tp) {
ad.emplace_back((qu){it.x, nq.x, it.v + nq.v});
}
skip :
solve(l, mid);
solve(mid + 1, r);
}
void mian() {
cin >> n;
vector <int> t;
for (int i = 1; i <= n; i++) {
int x, y, v;
cin >> x >> y >> v;
p[++cp] = (info){x, y, v, 0};
t.emplace_back(x);
}
for (int i = 1; i <= n; i++) {
int x, y, v;
cin >> x >> y >> v;
p[++cp] = (info){x, y, v, 1};
t.emplace_back(x);
}
sort(p + 1, p + cp + 1);
// for (int i = 1; i <= cp; i++) cerr << p[i].x << " " << p[i].y << " " << p[i].v << "\n";
cin >> q;
for (int i = 1; i <= q; i++) {
int l, r;
cin >> l >> r;
f[i] = (qu){l + 1, r - 1, i};
g[i] = (qu){l - 1, r + 1, i};
t.emplace_back(r - 1);
t.emplace_back(r + 1);
}
sort(all(t));
t.erase(unique(all(t)), t.end());
m = (int)t.size();
for (int i = 1; i <= q; i++) {
f[i].r = lower_bound(all(t), f[i].r) - t.begin() + 1;
g[i].r = lower_bound(all(t), g[i].r) - t.begin() + 1;
}
solve(1, cp);
// for (int i = 1; i <= cp; i++)
// for (int j = i + 1; j <= cp; j++) {
// if (p[i].c == 0 && p[j].c == 1 && p[i].y < p[j].y)
// ad.emplace_back((qu){p[i].x, p[j].x, p[i].v + p[j].v});
// }
sort(f + 1, f + q + 1);
sort(g + 1, g + q + 1);
sort(all(ad));
for (auto &it : ad) {
// cerr << it.l << " " << it.r << " " << it.v << "\n";
it.r = lower_bound(all(t), it.r) - t.begin() + 1;
}
// for (int i = 1; i <= q; i++) cerr << f[i].l << " " << f[i].r << "\n";
// for (int i = 1; i <= q; i++) cerr << g[i].l << " " << g[i].r << "\n";
int j = -1;
for (int i = 1; i <= q; i++) {
while (j + 1 <= (int)ad.size() - 1 && ad[j + 1].l <= g[i].l) {
j++;
bit2.mdf(ad[j].r, ad[j].v);
}
int id = g[i].v;
chkmx(ans[id], bit2.qry(g[i].r));
}
j = (int)ad.size();
for (int i = q; i >= 1; i--) {
while (j - 1 >= 0 && ad[j - 1].l >= f[i].l) {
j--;
bit1.mdf(ad[j].r, ad[j].v);
}
int id = f[i].v;
chkmx(ans[id], bit1.qry(f[i].r));
}
for (int i = 1; i <= q; i++) {
if (ans[i]) cout << ans[i] << "\n";
else cout << "-1\n";
}
}
int main() {
// fprintf(stderr, "%.9lfMb\n", 1.0 * (&Mbe - &Med) / 1048576.0);
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
while (t--) mian();
// cerr << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n"
return 0;
}
/*
10
-938 384 791666563
-455 810 540901345
-610 304 571352843
-275 659 601032507
-656 671 293799305
-996 42 519936324
-936 642 100753947
-148 395 135697693
-497 230 567339928
-763 366 395745738
421 613 224178644
315 508 47903043
880 227 41177958
313 572 723249693
733 346 885684010
838 169 429859587
464 707 601508208
27 525 246679278
197 182 351233408
766 739 495575770
1
-333 696
*/