Farmer John 由于对整理他难以整平的头发感到疲惫,于是决定去理发。他有一排 N 缕头发,第 i缕头发初始时长度为 A_i 微米理想情况下,他想要他的头发在长度上单调递增,所以他定义他的头发的“不良度”为逆序对的数量:满足 i < 及 A_i > A_j的二元对 (i,j)(i,j)。
对于每一个 j=0,1,…,N−1,Farmer John 想要知道他所有长度大于 j的头发的长度均减少到 j时他的头发的不良度。
题目可以理解为头发长度最长为 j 时3的逆序对数量。对于头发长度为n
时的逆序对数,同样是对其后面大于n
的情况下的贡献度。从小到达枚举j
,每次累计贡献度。
例如,当 j 为 3时,我们求得每个3前大于3(即为4与4+)的数字个数之和,也就是 j 等于4时增加的逆序对数。以此类推。
对于求逆序对。我们可以使用树状数组。设原序列为a[N]
,将序列 a 从小到大排列。1~n
个位置对应的树状数组上的数初始化为 1
每遍历到一个 a[i],将其在原序列中的位置 u
对应的树状数组的值改为 0,此时其贡献度为 u 之前1的个数sum(u-1)
,因比a[i]小的数会先遍历到,相应的树状数组的位置的值位置会置0,所以u
前还在的 1 均为比a[i]大的数。
#include
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
int n, m, k, t;
int tr[N];
struct node
{
int val, num;
}q[N];
bool cmp(node a, node b)
{
if(a.val == b.val) return a.num < b.num;
return a.val < b.val;
}
int lowbit(int x)
{
return x & -x;
}
void add(int x, int c)
{
for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}
int sum(int x)
{
int res = 0;
for(int i = x; i; i -= lowbit(i)) res += tr[i];
return res;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++)
{
int u;
cin >> u;
q[i].val = u;
q[i].num = i;
add(q[i].num, 1);
}
sort(q + 1, q + n + 1, cmp);
ll ans = 0, res = 1;
for(int i = 0; i < n; i ++)
{
cout << ans << "\n";
int tem = res;
while(i == q[tem].val)
{
ans += sum(q[tem].num - 1);
add(q[tem].num, - 1);
tem ++;
}
res = tem;
}
return 0;
}