hdu5792 World is Exploding(多校第五场)树状数组求逆序对 离散化

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5792

题目描述:给你n个值,每个值用A[i]表示,然后问你能否找到多少组(a,b,c,d)四个编号,四个编号互不相同,然后a < b, c < d,a代表的值小于b代表的值,c代表的值大于d代表的值。

解题思路:先考虑a和b这两个编号,遍历每一个编号作为b,然后找到b前面有多少个小于b的值,就是对于这一个编号b合理的编号a,对于每一组a和b,就可以考虑c和d,能够满足条件c和d的很显然就是除去a和b整个序列有多少个逆序对,对吧。然后对于每一个b有x个a满足条件,所以对于当前b,能够满足条件的就是(x*所有的逆序对的个数 - 逆序对中包涵a和b的个数)。所有逆序对很容易就可以用树状数组求出来,x也就是b前面有多少个小于编号b代表的值得个数,也很容易求出来,然后包涵a和b个数的逆序对呢,a前面大于A[a]的个数和a后面小于A[a]的个数,b也是一样的。

设x为对于每个b满足条件的a的个数,na代表和a有关系的逆序对,nb代表和b有关系的逆序对,tot代表所有的逆序对个数,然后对于每一个b就有 tot*x - nb*x - (所有na的值)。

 

代码:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<cstring>
#include<queue>
#include<set>
#include<string>
#include<map>
#define inf 9223372036854775807
#define INF 9e7+5
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 5e4 + 5;
const int mod = 1e9 + 7;
const db eps = 1e-9;
ll n, c[maxn], a[maxn], num[maxn], tot, cc[maxn], lar[maxn], b[maxn];

struct pos {
    ll a, ord, la;
} q[maxn];

void init() {
    tot = 0;
    memset(c, 0, sizeof(c));
    memset(cc, 0, sizeof(cc));
    memset(lar, 0, sizeof(lar)); //这个数组好像不用初始化
}

ll lowbit(ll x) {
    return x & (-x); //求最低位
}

void updata(ll x, ll p, ll u[]) { //更新
    while (x <= maxn) {
        u[x] += p;
        x += lowbit(x);
    }
}

ll getsum(ll x, ll u[]) {
    ll ans = 0;
    while (x > 0) {
        ans += u[x];
        x -= lowbit(x);
    }
    return ans;
}
bool cmp1(const pos&a, const pos&b)
{
    return a.a<b.a;
}
bool cmp2(const pos&a, const pos&b){
    return a.ord<b.ord;
}

void solve() {
    while (cin >> n) {
        init();
        for (int i = 1; i <= n; i++) {
            scanf("%I64d", &q[i].a);
            q[i].ord = i;
        }
        int pp = 0; sort(q+1, q+1+n, cmp1);
        q[0].a = -1;
        for (int i = 1; i <= n; i++) { //离散化
            if (q[i].a != q[i-1].a) q[i].la = ++pp;
            else {
                q[i].la = pp;
            }
        }
        sort(q+1, q+1+n, cmp2);
        for (int i = 1; i <= n; i++) {
            lar[i] = i - getsum(q[i].la, c) - 1; //求出每个数前面
            updata(q[i].la, 1, c);              //有多少比他大的数
        }
        memset(c, 0, sizeof(c));
        for (int i = n; i >= 1; i--) {
            num[i] = getsum(q[i].la-1, c);          //求出每个数的
            updata(q[i].la, 1, c); tot += num[i]; //后面比他小的个数
        }
        ll ans = 0; memset(c, 0, sizeof(c));
        for (int i = 1; i <= n; i++) {
            ll tmp = getsum(q[i].la-1, c);   //对当前b满足条件的a的个数
            updata(q[i].la, 1, c);  
            ll tt = getsum(q[i].la-1, cc);  //求出和a有关系的逆序对
            updata(q[i].la, num[i] + lar[i], cc);//num[i]+lar[i]就是和a有关系的逆序对
            ans += tmp * tot - tt - (num[i]+lar[i])*tmp;//这里的num[i]+lar[i]是和b有关系的逆序对
        }
        cout << ans << endl;
    }
}

int main(){
    //cin.sync_with_stdio(false);
    //freopen("tt.txt", "r", stdin);
    //freopen("isharp.out", "w", stdout);
    solve();

    return 0;
}

  

posted @ 2016-08-02 20:20  ost_xg  阅读(296)  评论(0编辑  收藏  举报