[权值BIT] 小朋友排队

解题思路

每个小朋友需要交换的次数必然是左边比他大的 + 右边比他小的

用 权值BIT 维护前缀后缀再单独计算等差即可

主席树应该也是可以解决的

/*
    Zeolim - An AC a day keeps the bug away
*/

//#pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <sstream>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
using namespace std;
typedef long long ll;
typedef long double ld;
const int INF = 0x3f3f3f3f;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const int MAXN = 1e7 + 10;

ll arr[MAXN] = {0};
ll cnt[MAXN] = {0};
ll c[MAXN] = {0};

ll lobit(ll x)
{
    return x & -x;
}

void add(ll x, ll n)
{
    for(; x <= n; x += lobit(x))
        ++c[x];
}

ll ask(ll x)
{
    ll ret = 0;
    
	for( ; x; x -= lobit(x))
        ret += c[x];

    return ret;
}

int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);     cout.tie(0);
    //freopen("D://test.in", "r", stdin);
    //freopen("D://test.out", "w", stdout);

    ll n, ln = 0;

    cin >> n;

    for(int i = 1; i <= n; ++i)
    {
        cin >> arr[i];
        ++arr[i];
        ln = max(ln, arr[i]);
    }

    for(int i = n; i >= 1; --i)
    {
        int pos = arr[i];

        cnt[i] += ask(pos - 1);

        add(pos, ln);
    }

    memset(c, 0, sizeof(c));

    for(int i = 1; i <= n; ++i)
    {
        int pos = arr[i];

        cnt[i] += (ask(ln) - ask(pos));

        add(pos, ln);
    }

    ll ans = 0;

    for(int i = 1; i <= n; ++i)
    {
        //cout << cnt[i] << '\n';
        if(cnt[i])
        {
            ans += ( (1 + cnt[i]) * (cnt[i]) / 2 ) ;
        }
    }

    cout << ans << '\n';



    
    return 0;
}

 

posted @ 2019-05-05 10:50  张浦  阅读(100)  评论(0编辑  收藏  举报