POJ 1990 MooFest

题目

题意:有m头牛,每头牛有两个值,v和x,两两之间有一个值,设v分别为v1,v2,x为x1,x2,则它们之间的值为abs(x1-x2) * Max(v1,v2),求所有m*(m-1)/2对牛之间值的总和。

思路:咋看第一眼都是暴力这个优秀算法,不过暴力肯定是不行的,所以要树状数组优化

      我们可以先将牛以V排序,这时只需要考虑每一个 i 左右的X的情况

// #include<bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring> // for memset
#include <vector> // push_back() // vector<int>().swap(v);
#include <set> //multiset set<int,greater<int>> //big->small
#include <map>
#include <stack> // top()
#include <queue> // front() // priority_queue<T,vector<T>,greater<T> >
#include <cmath> // auto &Name : STLName  Name.
#include <utility>
#include <sstream>
#include <string> // __builtin_popcount (ans); // 获取某个数二进制位1的个数
#include <cstdlib> // rand()

#define IOS ios_base::sync_with_stdio(0); cin.tie(0)
using namespace std;
typedef long long ll;

int lowbit(int x){ return x&(-x);}

const int maxn = 20010;

struct Node
{
    int x,v;
    bool operator< (const Node& s)const{return v<s.v;}
}node[maxn];

int n;
int treeCount[maxn];
int treeDis[maxn];

ll sum(int x,int *t)
{
    ll ans=0;
    while(x)
    {
        ans+=t[x];
        x-=lowbit(x);
    }
    return ans;
}

void add(int x,int v,int *t)
{
    while(x<maxn)
    {
        t[x]+=v;
        x+=lowbit(x);
    }
}

ll solve()
{
    ll ans=0;
    ll totalDis=0;
    memset(treeCount , 0 , sizeof(treeCount));
    memset(treeDis , 0 , sizeof(treeDis));
    sort(node,node+n);

    for(int i=0;i<n;i++)
    {
        ll count=sum(node[i].x,treeCount);
        ll dis=sum(node[i].x,treeDis);

        ans+=node[i].v*(count*node[i].x-dis);
        ans+=node[i].v*((totalDis-dis-(i-count)*node[i].x));

        totalDis += node[i].x;
        add(node[i].x , 1 , treeCount);
        add(node[i].x , node[i].x , treeDis);
    }
    return ans;
}

int main(void)
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
            scanf("%d%d",&node[i].v,&node[i].x);
        printf("%lld
",solve());
    }

	return 0;
}

  

原文地址:https://www.cnblogs.com/jaszzz/p/12920316.html