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;
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章