题目大意:
给出 \(n\) 个点 \((a_i, b_i)\) ,问满足下列条件的 \((i, j)\) 有多少对:
- \(1 \leq i, j \leq n\)
- \(a_i \geq a_j\) && \(b_i \leq b_j\)
思路:
典型的二维偏序问题。
考虑类似离散化后用树状数组求逆序对的方法。那么我们要解决的问题就是如何处理等于关系。
我们以 \(b\) 作为关键字排序,然后逆序采用双指针,对于当前的下标 \(i\),将 \(b\) 相同的点加入到树状数组中(比 \(val[i].b\) 小的在之前加过了),然后我们要求有多少个点 \(val[j].a\) 满足 \(val[i].a \geq val[j].a\) ,那么就是求(离散化后)有多少个点在 \([0, val[i].a]\) 上。
for (int i = n, j = n; i >= 1; i--) {
while (j >= 1 && val[i].b == val[j].b) {
fen.add(getid(val[j].a, ta), 1);
j--;
}
ll tmp = fen.sum(getid(val[i].a, ta));
ans += tmp;
}
我们也可以顺序的采用双指针,对于当前的下标 \(i\),不同的是计算点的数量时,求(离散化后)有多少个点在 \([val[i].a, n]\) 上。
for (int i = 1, j = 1; i <= n; i++) {
while (j <= n && val[j].b == val[i].b) {
fen.add(getid(val[j].a, ta), 1);
j++;
}
ll tmp = fen.rangeSum(getid(val[i].a, ta) - 1, n);
ans += tmp;
}
Code:
template <typename T>
struct Fenwick {
const int n;
vector<T> a;
Fenwick(int n) : n(n), a(n + 1) {}
void add(int x, T v) {
for (int i = x; i <= n; i += i & -i) {
a[i] += v;
}
}
T sum(int x) {
T ans = 0;
for (int i = x; i > 0; i -= i & -i) {
ans += a[i];
}
return ans;
}
T rangeSum(int l, int r) {
return sum(r) - sum(l);
}
};
struct Node {
int a;
int b;
bool operator<(const Node &t) const {
return b < t.b;
}
};
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
cin >> n;
Fenwick<ll> fen(n);
vector<Node> val(n + 1);
vector<int> ta, tb;
auto getid = [&](int x, vector<int> &t) {
return lower_bound(t.begin(), t.end(), x) - t.begin() + 1;
};
for (int i = 1; i <= n; i++) {
cin >> val[i].a;
ta.emplace_back(val[i].a);
}
for (int i = 1; i <= n; i++) {
cin >> val[i].b;
tb.emplace_back(val[i].b);
}
sort(ta.begin(), ta.end());
ta.erase(unique(ta.begin(), ta.end()), ta.end());
sort(tb.begin(), tb.end());
tb.erase(unique(tb.begin(), tb.end()), tb.end());
sort(val.begin() + 1, val.end());
ll ans = 0;
for (int i = n, j = n; i >= 1; i--) {
while (j >= 1 && val[i].b == val[j].b) {
fen.add(getid(val[j].a, ta), 1);
j--;
}
ll tmp = fen.sum(getid(val[i].a, ta));
ans += tmp;
}
cout << ans << "\n";
return 0;
}