CodeForces: A. Inversions

217 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

题目描述

这是codeforces的线段树专题。

A - Segment Tree, part 1 - A. Inversions

Given a permutation pi of n elements, find for each ii the number of j such that j<i and pi<pj.

Input

The first line contains the number n (1≤n≤10^5), the second line contains n numbers pi. It is guaranteed that pi form a permutation of numbers from 1 to n.

Output

Print n numbers, the ii-th number is equal to the number of j such that j<i and pi<pj.

Example

input

5
4 1 3 5 2

output

0 1 1 0 3 

问题解析

经典题。翻转一下就是求逆序对了。

这题有个先决条件:元素都是1~n的。准备一个全为0的线段树,然后我们从左往右遍历数组,每遍历到一个元素a[i],就计算一下线段树中1到a[i]-1这个区间的和。和为多少就说明有多少比他小的数出现在它左边。然后我们把线段树中a[i]的位置从0变成1。

为什么区间的和为多少就说明有多少比他小的数出现在它左边?每走完一个元素就把它在线段树中对应的值从0变成1,然后我们计算的是1~ a[i]-1 这个区间的区间和,1~a[i]-1的数肯定都是小于a[i]的。所以这个区间的区间和就说明有多少比他小的数先出现,而我们是从左往右遍历数组的,所以和有多少就说明有多少比他小的数出现在它左边。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;
const int N = 100050;
int f[4 * N], a[N];

void revice(int k, int l, int r, int x)
{
    if (l == r)
    {
        f[k] = 1;
        return;
    }
    int m = (l + r) / 2;
    if (x <= m)revice(k + k, l, m, x);
    else revice(k + k + 1, m + 1, r, x);
    f[k] = f[k + k] + f[k + k + 1];
}
int calc(int k, int l, int r, int x, int y)
{
    if (x == l && y == r)return f[k];
    int m = (l + r) / 2;
    if (y <= m)return calc(k + k, l, m, x, y);
    else
        if (x > m)return calc(k + k + 1, m + 1, r, x, y);
        else return calc(k + k, l, m, x, m) + calc(k + k + 1, m + 1, r, m + 1, y);
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, m;
    cin >> n;
    for (int i = 1; i <= n; i++)cin >> a[i];
    vector<int>v(n);
    for (int i = 1; i <= n; i++)
    {
        v[i - 1] = calc(1, 1, n, a[i], n);
        revice(1, 1, n, a[i]);
    }
    for (auto i : v)cout << i << " ";
    return 0;
}