
奶牛节:N头奶牛每头耳背程度v,坐标x。两牛交流需要音量为distance * max(v(i),v(j)),求所有牛两两交流所需总和?
3.3活用各种数据结构
Binary Indexed Tree
要求{∀i with v[i]<v[j]} Σv[j]*|x[i]-x[j]|,也就是求 Σv[j]*(x[j]-x[i]){∀i with v[i]<v[j] and x[i]<x[j]} + Σv[j]*(x[i]-x[j]){∀i with v[i]<v[j] and x[j]<x[i]}。这里涉及到求和,而且求和的区间有重复,所以要利用树状数组。
这题用到了两个BIT,分别是个数BIT和距离BIT。将牛按照耳背程度升序后,一头一头地加入奶牛节。加入每一头的时候,这头牛的耳背程度肯定是最大的。那么就用这头牛的耳背程度乘以到所有牛的距离即可。每加入一头牛,就逐步构建BIT一次。
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX_N 20000 + 16
typedef long long LL;
pair<int, int> cow[MAX_N];
int N;
LL count_bit[MAX_N], distance_bit[MAX_N];	// 两个数组下标都是坐标,值用来统计牛的个数和距离
// 求和sum{a[t], 0 <= t <= i}
LL sum(LL* bit, int i)
{
	LL s = 0;
	while (i > 0)
	{
		s += bit[i];
		i -= i & -i;
	}
	return s;
}
// 求和a[from, to)
LL sum(LL* bit, int from, int to)
{
	return sum(bit, to - 1) - sum(bit, from - 1);
}
// 执行 a[i] += x
void add(LL* bit, int i, LL x)
{
	while (i <= MAX_N)
	{
		bit[i] += x;
		i += i & -i;
	}
}
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	cin >> N;
	for (int i = 0; i < N; ++i)
	{
		cin >> cow[i].first >> cow[i].second;
	}
	sort(cow, cow + N);
	LL result = 0;
	for (int i = 0; i < N; ++i)
	{
		// cow按v升序,v始终为最大
		int v = cow[i].first, x = cow[i].second;	// 自己的参数,取个短点好懂的名字
		LL left = sum(count_bit, 1, x), right = sum(count_bit, x + 1, MAX_N);	// 左右牛的个数
		result += v * ((left * x - sum(distance_bit, 1, x)) + (sum(distance_bit, x + 1, MAX_N) - right * x));
		add(count_bit, cow[i].second, 1);
		add(distance_bit, cow[i].second, cow[i].second);
	}
	cout << result << endl;
#ifndef ONLINE_JUDGE
	fclose(stdin);
	fclose(stdout);
	system("out.txt");
#endif
	return 0;
}
///////////////////////////End Sub//////////////////////////////////
| 12948268 | hankcs | 1990 | Accepted | 692K | 172MS | C++ | 1529B | 2014-06-05 00:57:32 | 
 码农场
码农场
只能说写得太好了,看其他人的都理解不到那个公式