zoukankan      html  css  js  c++  java
  • Luogu P2345 奶牛集会

    传送门

    这道题可以用分治的方法解决。(lbgxld说是线段树,但是我觉得分治快而且好写...)

    暴力枚举是$O(n^2)$,想要优化,就不能一对一对枚举,最好能用一只奶牛一次计算一群其他的贡献。

    这就需要考虑听力$v$和坐标大小$x$的关系,可以把它转化为一个二维偏序问题。

    首先把听力$v$从大到小排序,控制一维。

    然后用归并排序,按$x$从小到大排序。

    因为左边一半$(l,mid)$奶牛的$v$一定大于右边的$(mid+1,r)$,那么我们只计算左边的每一个对右边的贡献。

    也就是说,只有当左边的一个奶牛加入归并的数组时,才分别统计坐标比它小和比它大的贡献。

    对于左边的一个奶牛,设它的听力为$vi$,坐标为$xi$。

    设$s1$为右边所有$x$比$xi$小的的坐标之和  (初始为0);

    设$s2$为右边所有$x$比$xi$大的的坐标之和 (初始为$(mid+1,r)$的奶牛坐标之和)。

    归并排序的过程,就是不断选取$x$较小的奶牛加入归并数组中。

    如果枚举到右边的一个奶牛,不统计贡献;但要把$s1$加上它的$x$,$s2$减去它的$x$。

    如果枚举到左边的一个奶牛,统计贡献:

    已经统计出了有几只奶牛的坐标比$xi$小,而剩余的比$xi$大,

    要求坐标差的绝对值,答案即为$[ (xi*比它小的个数-s1)+(s2-xi*比它大的个数) ]* vi$(因为这个$vi$一定大于所有右边的)。

    因为两边已经按$x$从小到大排好,所以左边在$xi$之后的奶牛的坐标一定比$xi$大,也一定能对已经被加入$s1$中的奶牛做出贡献。

    一开始我想直接按二维偏序的方法做,只记录比当前坐标小的奶牛的贡献,也就是只用大的减小的,最后乘2。

    但是这道题并不是严格的偏序问题,它除了求逆序对还要求顺序对,这两个数量之和显然不是逆序对数量*2。

    代码如下

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define MogeKo qwq
    #include<algorithm>
    #define int long long
    using namespace std;
    const int maxn = 1e6;
    int n,ans;
    
    struct vx {
      int v,x;
      bool operator < (const vx & N) const {
        return v>N.v || ( v==N.v && x<N.x);
      }
    } a[maxn],b[maxn];
    
    void cdq(int l,int r) {
      if(l==r)return;
      int mid = (l+r)>>1;
      cdq(l,mid);
      cdq(mid+1,r);
      int s1 = 0,s2 = 0;
      for(int i = mid+1;i <= r;i++)
        s2 += a[i].x;
      int i = l,j = mid+1,k = l;
      while(i <= mid) {
        while(j <= r && a[i].x > a[j].x) {
          s1 += a[j].x;
          s2 -= a[j].x;
          b[k++] = a[j++];
        }
        ans += a[i].v*((j-mid-1)*a[i].x - s1 + s2 - (r-j+1)*a[i].x);
        b[k++] = a[i++];
      }
      while(j <= r)
        b[k++] = a[j++];
      for(int i = l; i <= r; i++)
        a[i] = b[i];
    }
    
    main() {
      scanf("%lld",&n);
      for(int i = 1; i <= n; i++)
        scanf("%lld%lld",&a[i].v,&a[i].x);
      sort(a+1,a+n+1);
      cdq(1,n);
      printf("%lld
    ",ans);
    }
    View Code

     

  • 相关阅读:
    poj 2352 Stars(线段树)
    poj 2029 Get Many Persimmon Trees
    .Net remoting 的解答,以及跟WebService的区别
    关于Xcode4.2中的release“不能”使用的理解
    委托的学习日志
    钩子是啥?以及用来说啥,是不是可以用来做即时通讯?
    C#后台程序与HTML页面中JS方法互调(功能类似于Ajax中的DWR)
    接触了一下项目管理系统软件:禅道项目管理软件、Bugfree
    将string变为int 的几种方法方法比较
    Hashtable、Dictionary、SortedDictionary、SortedList的比较应用
  • 原文地址:https://www.cnblogs.com/mogeko/p/10943622.html
Copyright © 2011-2022 走看看