CH4201 楼兰图腾 树状数组与逆序对问题

题目大意

给定一个长度为n的序列, 
1.求所有点的左边右边比它大的数的个数, 两边的个数相乘, 所有的点求和, 
2.求所有点的左边右边比它小的数的个数, 两边的个数相乘, 所有的点求和, 

样例

输入样例:
5
1 5 3 2 4
输出样例:
3 4

思路

利用树状数组求逆序对

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

typedef long long ll;
const int N = 200010;

ll c[N], r[N], l[N], a[N];
ll ans1, ans2;
int n;
 
int lowbit(int x)
{
	return x & -x;
}

void add(int x, int v)
{
	for(int i = x; i <= n; i += lowbit(i))
		c[i] += v;
}

int query(int x)
{
	int ans = 0;
	for(int i = x; i > 0; i -= lowbit(i))
		ans += c[i];
	return ans;
}

int main()
 {
 	scanf("%d", &n);
 	for(int i = 1; i <= n; i++)
 		scanf("%d", a + i);
 	for(int i = 1; i <= n; i++)
 	{
 		l[i] = query(a[i] - 1);
		add(a[i], 1);	
	}
	memset(c, 0, sizeof c);
	for(int i = n; i > 0; i--)
	{
		r[i] = query(a[i] - 1);
		add(a[i], 1);
	}
	for(int i = 1; i <= n; i++)
		ans1 += l[i] * r[i];
	
	memset(c, 0, sizeof c);
	for(int i = 1; i <= n; i++)
	{
		l[i] = query(n) - query(a[i]);
		add(a[i], 1);
	}
	
	memset(c, 0, sizeof c);
	for(int i = n; i >= 1; i--)
	{
		r[i] = query(n) - query(a[i]);
		add(a[i], 1);
	}
	for(int i = 1; i <= n; i++)
		ans2 += l[i] * r[i];
	printf("%lld %lld", ans2, ans1);
 	return 0;
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章