题目链接:Leetcode493
思路:同求逆序数一样的更新查询,关键在于离散化部分,我们要得到原序列与2倍序列所对应的位置,并且为了最后能够常数时间查到原序列对应位置的2倍序列的数值的位置,用个哈希函数 i d % n id\%n id%n表示同位置的对应的位置,设一个rnk1表示原序列位置,rnk2表示2倍序列的位置,题就解决了。关于离散化那个用二分处理的可能不好操作,用结构体排序会快点
Code:
class Discretization {
public:
int id; //组号
//小于n表示第i组原序列 大于n表示第i%n组原序列得2倍
long long val;
bool operator < (const Discretization& A) {
return val < A.val;
}
};
class Solution {
public:
int reversePairs(vector<int>& nums) {
n = nums.size();
memset(c, 0, sizeof(c));
//关键:离散化
//找到原序列和2倍原序列对应得位置
for (int i=0; i<n; i++) {
discrete[i].id=i;
discrete[i].val=nums[i];
discrete[i+n].id=i+n;
discrete[i+n].val=nums[i]*2LL;
}
sort(discrete, discrete+2*n);
int tag=0; //去重标记
for (int i=0; i<2*n; i++) { //预处理两个序列的离散化序列
if (i==0 || discrete[i].val!=discrete[i-1].val) tag++;
if (discrete[i].id<n) rnk1[discrete[i].id]=tag;
else rnk2[discrete[i].id-n]=tag;
}
int ans = 0;
for (int i = 0; i < n; i++) {
ans += i-query(rnk2[i]); //查询两倍i的数所得到的贡献
update(rnk1[i], 1); //i位置对后面的贡献
}
return ans;
}
private:
int c[100005], n;
Discretization discrete[100005];
int rnk1[50005],rnk2[50005];
inline int lowbit(int x) {
return x & (-x);
}
void update(int idx, int num) {
while(idx <= 100000) {
c[idx] += num;
idx += lowbit(idx);
}
}
int query(int idx) {
int sum = 0;
while (idx > 0) {
sum += c[idx];
idx -= lowbit(idx);
}
return sum;
}
};