离散化,树状数组,大数简单输出

题意:

珂朵莉给了你一个序列,有图片说明 个子区间,求出她们各自的逆序对个数,然后加起来输出

输入描述:
第一行一个数 n 表示这个序列 a 的长度

之后一行 n 个数,第i个数表示ai

输出描述:
输出一行一个数表示答案

分析:

树状数组进阶中!!!!!!!!!
这题大佬们已经分析的很清楚了。
考虑贡献,对于一个逆序对(i,j)他在整个计算中的贡献为 : i(n-j+1)
当我们固定j,找到所有与j搭配的i
(i1,j)、(i2,j)、(i3,j)。。。。。。
那么总贡献便为:(i1+i2+i3+......)
(n-j+1)
sum(i)*(n-j+1)
这里的这个i是在我们遍历到j之前遍历到的比j大的元素的下标
如此我们可以用树状数组维护!!!!
因为实在是太多了,所以我们离散,排序确定大小关系后重新编号

拿这题坑的就是,他会爆long long
致命、致命
曾在一个大佬的题解那学了一个简单的爆long long 的处理方法
我们用两个long long来存储ans1,ans2
ans2存储1e18的倍数,ans1存储1e18的余数
这样输出的时候我们就先输出ans2再输出ans1,注意ans1输出时要保证长度为18高位补零

代码如下

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int max_n = 1e6 + 100;
const ll mx = 1e18;
ll BIT[max_n];
int a[max_n];
int b[max_n];

void renew(int x,int num) {
    for (;x < max_n;x += (x & -x))BIT[x] += (ll)num;
}

ll quiry(int x) {
    ll res = 0;
    for (;x;x -= (x & -x))res += BIT[x];
    return res;
}

int main() {
    ios::sync_with_stdio(0);
    int n;cin >> n;
    map<int, int> ls;
    for (int i = 1;i <= n;i++)
        cin >> a[i], b[i] = a[i];
    sort(b + 1, b + 1 + n);
    int total = 1;
    for (int i = 1;i <= n;i++)
        if (ls.find(b[i]) == ls.end())ls[b[i]] = total++;
    for (int i = 1;i <= n;i++)
        a[i] = ls[a[i]];
    ll ans1 = 0;ll ans2 = 0;
    for (int i = 1;i <= n;i++) {
        ll tmp = quiry(max_n-1) - quiry(a[i]);
        ans1 += tmp * ((ll)n - i + 1);
        renew(a[i],i);
        if (ans1 >= mx) { ans2 += ans1 / mx;ans1 %= mx; }
    }
    if (ans2) {
        cout << ans2;
        cout.fill('0');cout.width(18);
        cout << ans1 << endl;
    }
    else cout << ans1 << endl;
}