You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
2.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
树状数组解法 https://blog.csdn.net/m0_50299150/article/details/122729602
权值线段树解法
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 10;
int a[N], b[N];
int n;
// 344 ms
struct Node {
int l, r; //描述的范围[l,r]
int sum; // l,r之间数字的个数
} tr[N << 2]; // 线段树需要开4倍的空间
void build(int u, int l, int r) {
tr[u] = {l, r, 0};
if (l == r) return;
int mid = (l + r) >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void pushup(int u) {
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void modify(int u, int p, int v) {
if (tr[u].l == p && tr[u].r == p) {
tr[u].sum += v;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (p <= mid)
modify(u << 1, p, v);
else
modify(u << 1 | 1, p, v);
//更新父节点信息
pushup(u);
}
int query(int u, int l, int r) {
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(u << 1 | 1, l, r);
else {
if (r <= mid)
return query(u << 1, l, r);
else
return query(u << 1, l, mid) + query(u << 1 | 1, mid + 1, r);
}
}
int main() {
//本题如果使用vector+离散化在AcWing可以正常AC但在洛谷会有很多TLE目前想来原因可能是因为vector的性能导致
//如果采用静态的数组进行离散化处理,就不会有这个问题
cin >> n;
//一般我们使用线段树都喜欢从下标1开始所以我们在处理数据时尽量让下标从1开始
for (int i = 1; i <= n; i++) cin >> a[i], b[i] = a[i];
sort(a + 1, a + n + 1); //对原始数组进行排序
//这里没有进行离散化,只是对数据重新规范到范围[1,n]之间
for (int i = 1; i <= n; i++) b[i] = lower_bound(a + 1, a + n + 1, b[i]) - a;
LL ans = 0;
//创建线段树
build(1, 1, n + 1);
//边查边添加,查找它后面比它大的数字个数
for (int i = 1; i <= n; i++) {
ans += query(1, b[i] + 1, n + 1);
modify(1, b[i], 1);
}
//输出答案
cout << ans << endl;
return 0;
}