1 定义
2 实现
3 应用-剑指 Offer 51. 数组中的逆序对
#define lson rt<<1 // 左儿子
#define rson rt<<1|1 // 右儿子
#define Lson l,m,lson // 左子树
#define Rson m+1,r,rson // 右子树
const int max_n = 50010;
int arr[max_n], backup[max_n];
struct Seg {
long long sum, lazy;
} seg[max_n<<2];
void pushup(int rt){
seg[rt].sum = seg[lson].sum + seg[rson].sum;
}
void pushdown(int rt, int m){
if(seg[rt].lazy == 0) return;
seg[lson].lazy += seg[rt].lazy;
seg[rson].lazy += seg[rt].lazy;
seg[lson].sum += seg[rt].lazy * (m - (m >> 1));
seg[rson].sum += seg[rt].lazy * (m >> 1);
seg[rt].lazy = 0;
}
void build(int l, int r, int rt){
if (l > r) {
return;
}
seg[rt].lazy = 0;
if(l == r) { seg[rt].sum = 0; return; }
int m = (l + r) >> 1;
build(Lson); build(Rson);
pushup(rt);
}
void update(int L, int R, long long add, int l, int r, int rt) {
if (L > R || l > r) {
return;
}
if(L <= l && r <= R) {
seg[rt].lazy += add;
seg[rt].sum += add * (r - l + 1);
return;
}
pushdown(rt, r - l + 1);
int m = (l + r) >> 1;
if(L <= m) update(L, R, add, Lson);
if(m < R) update(L, R, add, Rson);
pushup(rt);
}
long long query(int L, int R, int l, int r, int rt) {
if (L > R || l > r) return 0;
if(L <= l && r <= R) return seg[rt].sum;
pushdown(rt, r - l + 1);
long long m = (l + r) >> 1, res = 0;
if(L <= m) res += query(L, R, Lson);
if(m < R) res += query(L, R, Rson);
return res;
}
//类似题目:https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/
class Solution {
public:
int reversePairs(vector<int>& nums) {
int n = nums.size();
if (n < 2)
return 0;
for (int i = 0; i < n; ++i)
backup[i] = nums[i];// 对输入数组 nums 进行备份
sort(nums.begin(), nums.end()); // 对输入数组进行排序,sort是使用的快速排序,是本地排序,所以会对input进行修改,所以先对input进行了备份
int sz = unique(nums.begin(), nums.end()) - nums.begin();//去重
int max_val = 0;
for (int i = 0; i < n; ++i)
{
arr[i] = lower_bound(nums.begin(), nums.begin() + sz, backup[i]) - nums.begin() + 1; //这一步实际上就是离散化,将离散化的数据保存到“预处理数组”arr中
max_val = max(max_val, arr[i]);//针对数值的大小做一个排名的「映射」,把原始数据映射到 [1, sz] 这个区间,这样「线段树」底层的数组空间会更紧凑,更易于维护
}
//建立线段树,这里实际上只是构建了一个空的线段树,后面会利用“预处理数组”来更新这个线段树
build(1, max_val, 1);
//只需要使用“预处理数组”就可以得到结果
int ans = 0;
for (int i = n - 1; i >= 0; --i)
{
update(arr[i], arr[i], 1, 1, max_val, 1);
ans += query(1, arr[i] - 1, 1, max_val, 1);
}
return ans;
}
};