POJ-1990 MooFest---两个树状数组

题目链接:

https://vjudge.net/problem/POJ-1990

题目大意:

一群牛参加完牛的节日后都有了不同程度的耳聋,第i头牛听见别人的讲话,别人的音量必须大于v[i],当两头牛i,j交流的时候,交流的最小声音为max{v[i],v[j]}*他们之间的距离。现在有n头牛,求他们之间两两交流最少要的音量和。

解题思路:

使用树状数组,首先将二元组按照v的大小从小到大排序,这样可以保证每头牛比前面的牛的v大,计算它和它前面牛的音量和的时候,就可以直接用该头牛的v,还需要计算出|a[i].x - x|绝对值之和。

用树状数组维护坐标x,可以直接求出比这头牛小的所有x之和,还需要用另一个树状数组维护每个元素出现的次数,直接求出小于这头牛的x的牛的数目。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<map>
 6 #include<set>
 7 #include<cmath>
 8 #include<algorithm>
 9 #include<vector>
10 #include<sstream>
11 #define lowbot(i) (i&(-i))
12 using namespace std;
13 typedef long long ll;
14 const int maxn = 1e5 + 10;
15 struct cow
16 {
17     ll v, x;
18     bool operator <(const cow& a)const
19     {
20         return v < a.v || v == a.v && x < a.x;
21     }
22 }a[maxn];
23 int tree[maxn], id_num[maxn];
24 void add(int x, int d, int tree[])
25 {
26     while(x <= maxn)//上限是maxn
27     {
28         tree[x] += d;
29         x += lowbot(x);
30     }
31 }
32 ll sum(int x, int tree[])
33 {
34     ll ans = 0;
35     while(x)
36     {
37         ans += tree[x];
38         x -= lowbot(x);
39     }
40     return ans;
41 }
42 int main()
43 {
44     int n;
45     scanf("%d", &n);
46     for(int i = 0; i < n; i++)scanf("%lld%lld", &a[i].v, &a[i].x);
47     sort(a, a + n);
48     ll num, tot, ans = 0;
49     for(ll i = 0; i < n; i++)
50     {
51         num = sum(a[i].x, id_num);
52         tot = sum(a[i].x, tree);
53         ans += (num * a[i].x - tot) * a[i].v;
54         //cout<<num<<" - "<<tot<<" + "<<ans<<endl;
55         num = i - num;
56         tot = sum(20000, tree) - tot;
57         ans += (tot - num * a[i].x) * a[i].v;
58         //cout<<num<<" - "<<tot<<" - "<<ans<<endl;
59         add(a[i].x, a[i].x, tree);
60         add(a[i].x, 1, id_num);
61     }
62     cout<<ans<<endl;
63     return 0;
64 }

 

posted @ 2018-04-26 21:09  _努力努力再努力x  阅读(349)  评论(0编辑  收藏  举报