TZOJ1614 MooFest详解(树状数组)

具体题目请点TZOJ1614

 

题目简述

  有N头牛,它们在同一行上且位于不同的位置,求每两头牛产生值的总和。

题解

  暴力的话双重循环O(n^2),当然会T了。此时我们就得找别的方法。通过观察我们可以发现Vi越大这头牛的贡献就越大,所以我们可以按照Vi从大到小,逐个计算,每计算一个放走一头牛。我们可以证明

 

 

 

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
 4 typedef long long ll;
 5 const ll N=2e4+7;
 6 const ll INF=1e18;
 7 int n;
 8 ll num1,num2; //得到右边和左边牛的个数 
 9 ll dist[N];   //树状数组用来记录牛坐标 
10 int flag[N];  //树状数组用来记录牛的头数 
11 struct F{
12     ll val; //牛的权值 
13     ll pos; //牛在的位置 
14     int tt; //用来映射到树状数组中的第一位置 
15 }zt[N];
16 bool cmp(const F &a,const F &b){ //以牛在坐标的位置从小到大排序 
17     return a.pos<b.pos;
18 }
19 bool cmp2(const F &a,const F &b){ //以牛的权值从大到小排序 
20     return a.val>b.val;
21 }
22 int lowbit(int x){
23     return x&(-x);
24 }
25 void update(int k,int pos,int x){ //常规更新操作 
26     while(pos<=n){
27         dist[pos]+=k;
28         flag[pos]+=x;
29         pos+=lowbit(pos);
30     }
31 }
32 ll get(int pos){ //查询牛的右边(实际上是整个队伍) 
33     ll res=0;
34     while(pos>0){
35         res+=dist[pos];
36         num1+=flag[pos];
37         pos-=lowbit(pos);
38     }
39     return res;
40 }
41 ll get2(int pos){ //查询牛的左边
42     ll res=0;
43     while(pos>0){
44         res+=dist[pos];
45         num2+=flag[pos];
46         pos-=lowbit(pos);
47     }
48     return res;
49 }
50 void sovle(){
51     cin>>n;
52     for(int i=1;i<=n;i++){
53         cin>>zt[i].val>>zt[i].pos;
54     }
55     sort(zt+1,zt+1+n,cmp);
56     for(int i=1;i<=n;i++){
57         zt[i].tt=i;
58         update(zt[i].pos,i,1);
59     }
60     sort(zt+1,zt+1+n,cmp2);
61     ll res=0;
62     for(int i=1;i<n;i++){
63         num1=0;num2=0;
64         ll x=get(n),y=get2(zt[i].tt-1);
65         res+=(x-y-(num1-num2)*zt[i].pos)*zt[i].val;  //右边的总值 
66         res+=(num2*zt[i].pos-y)*zt[i].val;            //左边的总值 
67         update(-zt[i].pos,zt[i].tt,-1); //这头牛已经开会结束了,可以走了 
68     }
69     cout<<res<<endl;
70 }
71 int main(){
72     IOS;
73     int t=1;
74     while(t--){
75         sovle();
76     }
77     return 0;
78 }
79 /*
80 5
81 2 1
82 2 5
83 2 3
84 2 9
85 2 7
86 
87 80
88 */
View Code

 

posted on 2022-05-16 21:08  Feintl  阅读(71)  评论(2编辑  收藏  举报