std::vector<int> a, temp;
int n;
i64 merge(int left, int mid, int right){
inti(left), j(mid), k(left);
i64 count(0);
while(i <= mid - 1and j <= right) {
if (a[i] < a[j]) {
temp[k++] = a[i++];
}
else {//因为题目要求a[i] >= a[j] temp[k++] = a[j++];
count += mid - i;//又因为合并操作已保证左区间有序,所以i之后到mid的a[i]都大于等于a[j] }
}
while(i <= mid - 1)
temp[k++] = a[i++];
while(j <= right)
temp[k++] = a[j++];
for (i = left; i <= right; i++)
a[i] = temp[i];
return count;
}
i64 mergeSort(int left, int right){
intmid(0);
i64 count(0);
if (right > left) {
mid = left + right >> 1;
count = mergeSort(left, mid);
count += mergeSort(mid + 1, right);
count += merge(left, mid + 1, right);
}
return count;
}
i64 aInversion(int n){
temp.resize(n);
returnmergeSort(0, n - 1);
}
voidsolve(){
std::cin >> n;
a.resize(n);
for (auto& x : a) std::cin >> x;
std::cout << aInversion(n) << '\n';
}
3|0树状数组or线段树
题目说了
考虑用 来作为一段 前缀和中 的下标,即通过前缀和来计数
从后往前扫,每次先查询包括该下标到 (因为要求 )的前缀和,显然就是对于当前数字的逆序对个数
树状数组
template <typename T>
structFenwick {
int n;
std::vector<T> a;
Fenwick(int n_ = 0) {
init(n_);
}
voidinit(int n_){
n = n_;
a.assign(n, T{});
}
voidadd(int x, const T &v){
for (int i = x + 1; i <= n; i += i & -i) {
a[i - 1] = a[i - 1] + v;
}
}
T sum(int x){
T ans{};
for (int i = x; i > 0; i -= i & -i) {
ans = ans + a[i - 1];
}
return ans;
}
};
voidsolve(){
int n;
std::cin >> n;
Fenwick<int> fen(n);
std::vector<int> a(n);
for (auto& x : a) std::cin >> x, x--;
i64 ans(0);
for (int i = n - 1; i >= 0; i--) {
ans += fen.sum(a[i] + 1);//这里是因为前面对数据做了--防越界处理,而该fenwick的实现中查询是右开的 fen.add(a[i], 1);
}
std::cout << ans << '\n';
}
线段树
template<classInfo>
structSegmentTree {
int n;
std::vector<Info> info;
SegmentTree() : n(0) {}
SegmentTree(int n_, Info v_ = Info()) {
init(n_, v_);
}
template<class T>
SegmentTree(std::vector<T> init_){
init(init_);
}
voidinit(int n_, Info v_ = Info()){
init(std::vector(n_, v_));
}
template<class T>
voidinit(std::vector<T> init_){
n = init_.size();
info.assign(4 << std::__lg(n), Info());
std::function<void(int, int, int)> build = [&](int p, int l, int r) {
if (r - l == 1) {
info[p] = init_[l];
return;
}
int m = (l + r) / 2;
build(2 * p, l, m);
build(2 * p + 1, m, r);
pull(p);
};
build(1, 0, n);
}
voidpull(int p){
info[p] = info[2 * p] + info[2 * p + 1];
}
voidmodify(int p, int l, int r, int x, const Info &v){
if (r - l == 1) {
info[p] = info[p] + v;
return;
}
int m = (l + r) / 2;
if (x < m) {
modify(2 * p, l, m, x, v);
} else {
modify(2 * p + 1, m, r, x, v);
}
pull(p);
}
voidmodify(int p, const Info &v){
modify(1, 0, n, p, v);
}
Info rangeQuery(int p, int l, int r, int x, int y){
if (l >= y || r <= x) {
returnInfo();
}
if (l >= x && r <= y) {
return info[p];
}
int m = (l + r) / 2;
returnrangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
}
Info rangeQuery(int l, int r){
returnrangeQuery(1, 0, n, l, r);
}
};
structInfo {
i64 sum;
};
Info operator+(Info a, Info b) {
a.sum += b.sum;
return a;
}
voidsolve(){
int n;
std::cin >> n;
std::vector<int> a(n);
for (auto& x : a) std::cin >> x, x--;
i64 ans(0);
SegmentTree<Info> T(n + 1);
for (int i = n - 1; i >= 0; i--) {
ans += T.rangeQuery(0, a[i] + 1).sum;//这里是因为前面对数据做了--防越界处理,而该segmentTree的实现中查询是左闭右开的 T.modify(a[i], {1});
}
std::cout << ans << '\n';
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下