Files
python/TangDou/AcWing/Sort/788_XDS.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

82 lines
2.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 权值线段树解法
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 10;
int a[N], b[N];
int n;
// 线段树区间和模板
#define ls u << 1
#define rs u << 1 | 1
struct Node {
int l, r; // 范围
int sum; // 区间内数字个数
} tr[N << 2]; // 4倍空间
// 创建
void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r;
if (l == r) return;
int mid = l + r >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
}
// 向上更新统计信息
void pushup(int u) {
tr[u].sum = tr[ls].sum + tr[rs].sum;
}
// 修改点的值
void modify(int u, int x, int v) {
if (tr[u].l == x && tr[u].r == x) {
tr[u].sum += v;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid)
modify(ls, x, v);
else
modify(rs, x, v);
pushup(u);
}
// 查询区间和
int query(int u, int l, int r) {
if (l > r) return 0;
if (tr[u].l == l && tr[u].r == r) return tr[u].sum;
int mid = tr[u].l + tr[u].r >> 1;
if (mid < l) return query(rs, l, r);
if (r <= mid) return query(ls, l, r);
return query(ls, l, mid) + query(rs, mid + 1, r);
}
LL ans;
int main() {
cin >> n;
// 一般使用线段树,都喜欢从下标1开始,所以我们在处理数据时尽量让下标从1开始
// b[]在下面的代码中有两个阶段的含义,目前的含义是a[i]的备份,因为一会a[]由小到大排序后,原始数组就丢失了位置信息就不见了,需要b备份出来
for (int i = 1; i <= n; i++) cin >> a[i], b[i] = a[i];
// ① 原始数组由小到大排序
sort(a + 1, a + n + 1);
// ② 离散化,遍历原始数组b[i],找出它的排名,即b[2]=3表示第2个输入的是排名第3的
for (int i = 1; i <= n; i++) b[i] = lower_bound(a + 1, a + n + 1, b[i]) - a;
// 构建线段树
build(1, 1, n); // n个数字
// 边查边添加
for (int i = 1; i <= n; i++) {
modify(1, b[i], 1); // 占据b[i]这个位置
ans += query(1, b[i] + 1, n); // 出现的比我早,号还比我大的有多少个
}
// 输出
printf("%lld\n", ans);
return 0;
}