• p2345 奶牛集会


    传送门

    题目

    约翰的N 头奶牛每年都会参加“哞哞大会”。哞哞大会是奶牛界的盛事。集会上的活动很

    多,比如堆干草,跨栅栏,摸牛仔的屁股等等。它们参加活动时会聚在一起,第i 头奶牛的坐标为Xi,没有两头奶牛的坐标是相同的。奶牛们的叫声很大,第i 头和第j 头奶牛交流,会发出max{Vi; Vj}×|Xi − Xj | 的音量,其中Vi 和Vj 分别是第i 头和第j 头奶牛的听力。假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。

    输入格式:

    • 第一行:单个整数N,1 ≤ N ≤ 20000

    • 第二行到第N + 1 行:第i + 1 行有两个整数Vi 和Xi,1 ≤ Vi ≤ 20000; 1 ≤ Xi ≤ 20000

    输出格式:

    • 单个整数:表示所有奶牛产生的音量之和

    分析

    因为每一次的v取的是两个牛之间的最大值,所以我们先按牛的v从小到大排序,这样我们便无需考虑取最大值的问题,每一次只找在这只牛之前加入树状数组中的牛即可。然后我们在考虑如何计算每只牛所造成的影响,因为需要的是两个牛之间的距离即x的绝对值,所以我们每一次将每一只牛添加到树状数组中这只牛的坐标x的位置,我们用树状数组c1记录某个位置之前所有点的坐标和,c2记录某个位置之前有多少个点。我们将每一次查询分成两半:在这个点之前的和在这个点之后的,这样我们便无限考虑绝对值的问题,前半段为(之前的点的数量)*x-(之前点的坐标和),后半段为(之后点的坐标和)-(之后点的数量)*x,前半段的一切信息是最朴素的树状数组查询,而后半段的信息即为整段信息-前半段信息。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    struct node{
          long long v,x;
    }a[110000];
    long long c1[110000],c2[110000],n,ans,m;
    long long lb(long long x){return x&(-x);}
    bool cmp(const node &q,const node &p){
          return q.v<p.v;
    }
    long long w(long long x){
          long long t=0;
          while(x){
            t+=c1[x];
            x-=lb(x);
          }
          return t;
    }
    long long s(long long x){
          long long t=0;
          while(x){
            t+=c2[x];
            x-=lb(x);
          }
          return t;
    }
    void add(long long x,long long s,long long t){
          while(x<=m){
            c1[x]+=s;
            c2[x]+=t;
            x+=lb(x);
          }
    }
    long long q(long long x,long long v){
          return v*(s(x)*x-w(x));
    }
    long long q2(long long x,long long y,long long v){
          return v*(w(y)-w(x)-x*(s(y)-s(x)));
    }
    int main()
    {     long long i,j,k;
          scanf("%lld",&n);
          for(i=1;i<=n;i++){
             scanf("%lld%lld",&a[i].v,&a[i].x);
             m=max(m,a[i].x);
          }
          sort(a+1,a+n+1,cmp);
          for(i=1;i<=n;i++){
             ans+=q(a[i].x,a[i].v)+q2(a[i].x,m,a[i].v);
             add(a[i].x,a[i].x,1);
          }
          printf("%lld
    ",ans);
          return 0;
    }

     

  • 相关阅读:
    [剑指 Offer 11. 旋转数组的最小数字]
    进程描述符(PCB)
    [剑指 Offer 57. 和为s的两个数字]
    Linux netstat命令
    kafka2.3.X配置文件
    docker
    shell操作mysql数据库
    Linux文件查找之find命令
    sed 切割日志文件
    Linux文本处理之awk
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/9128099.html
Copyright © 2020-2023  润新知