码迷,mamicode.com
首页 > 编程语言 > 详细

poj 1990 树状数组

时间:2019-05-13 23:26:15      阅读:245      评论:0      收藏:0      [点我收藏+]

标签:pre   scanf   多少   mes   show   void   algorithm   iostream   部分   

传送门:https://vjudge.net/problem/POJ-1990

题意:m头牛,每头牛有两个值v和x。然后每两头牛之间的值是abs(x1-x2) * Max(v1,v2)。问所有m*(m-1)/2对牛之间值的总和。

白书上来的。就是用树状数组做。首先肯定是按照v排序,这样就可以不用管v了。接下来我们看看x。

我们先对所有牛的x排序,然后每头牛有一个idx代表这头牛的x在所有牛的x中排第几位。然后有两个树状数组,num[N]和dis[N]。num[i]表示比i小的有多少个,dis[i]表示比i小的x的和(这里的i指在X[N]数组排名第i位)。然后我按照v从小到大的顺序枚举每一头牛,每次进行维护,这样枚举到的牛所查询树状数组里的都是v比它小的。这样这头牛对答案的贡献就是由两部分构成。

第一部分x比它小的 就是比v×(x-xi)的和,整理就是v×(cnt×x-dis[i]),

然后我在记录目前为止总共加了多少个点进树状数组,以及这些点的x的总和totdis。

这样第二部分就是x比它大的就很好求了。

讲的可能不是很清楚,具体看代码吧。

技术图片
 1 // Cease to struggle and you cease to live
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <algorithm>
 7 #include <queue>
 8 #include <vector>
 9 #include <set>
10 #include <map>
11 #include <stack>
12 using namespace std;
13 typedef long long ll;
14 const int N=2e4+9;
15 int n;
16 ll num[N<<2],dis[N<<2],X[N];
17 void add(int x){
18     ll val=X[x];
19     for(;x<=n;x+=x&-x) dis[x]+=val,++num[x];
20 }
21 ll qnum(int x){
22     ll ans=0;
23     for(;x>0;x-=x&-x) ans+=num[x];
24     return ans;
25 }
26 ll qdis(int x){
27     ll ans=0;
28     for(;x>0;x-=x&-x) ans+=dis[x];
29     return ans;
30 }
31 struct cow{
32     ll v,x;
33     int idx;
34     bool operator<(const cow& b) const{
35         return v<b.v;
36     }
37 }a[N];
38 int main() {
39     scanf("%d",&n);
40     for(int i=1;i<=n;++i){
41         scanf("%lld%lld",&a[i].v,&a[i].x);
42         X[i]=a[i].x;
43     }
44     sort(X+1,X+1+n);
45     sort(a+1,a+1+n);
46     for(int i=1;i<=n;++i){
47         a[i].idx=lower_bound(X+1,X+1+n,a[i].x)-X;
48     }
49     ll totcnt=0,totdis=0;
50     ll res=0;
51     for(int i=1;i<=n;++i){
52         ll lcnt=qnum(a[i].idx);
53         ll ldis=qdis(a[i].idx);
54         res+=a[i].v*(lcnt*a[i].x-ldis);
55         res+=a[i].v*((totdis-ldis)-(totcnt-lcnt)*a[i].x);
56         ++totcnt;
57         totdis+=a[i].x;
58         add(a[i].idx);
59     }
60     printf("%lld",res);
61     return 0;
62 }
View Code

 

poj 1990 树状数组

标签:pre   scanf   多少   mes   show   void   algorithm   iostream   部分   

原文地址:https://www.cnblogs.com/xiaobuxie/p/10859430.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!