代码源:971、奶牛集会

252 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情 logo.png

题目描述

这是代码源5月28日的div2每日一题

奶牛集会 - 题目 - Daimayuan Online Judge

题目描述

约翰的 n 头奶牛每年都会参加“哞哞大会”。

哞哞大会是奶牛界的盛事。集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。

它们参加活动时会聚在一起,第 i 头奶牛的坐标为 xi,没有两头奶牛的坐标是相同的。

奶牛们的叫声很大,第 i 头和第 j 头奶牛交流,会发出 max{vi,vj}×|xi−xj| 的音量,其中 vi 和 vj 分别是第 i 头和第 j 头奶牛的听力。

假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。

输入格式

第 1 行:单个整数 n,1≤n≤3×10^4。

第 2 行到第 n+1 行:第 i+1 行有两个整数 vi 和 xi(1≤vi,xi≤3×10^4)。

输出格式

输出单个整数,表示所有奶牛产生的音量之和。

样例输入

4
3 1
2 5
2 6
4 3

样例输出

57

问题解析

1、暴力解法

数据量到了3*10 ^ 4,但是可以极限两层for循环暴力结束战斗(可能是数据比较弱罢)。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1e6;
int a[N];
vector<int>v[N];

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    cin >> n;
    vector<PII>v(n);
    ll res = 0;
    for (int i = 0; i < n; i++)cin >> v[i].first >> v[i].second;
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            res += max(v[i].first, v[j].first) * abs(v[i].second - v[j].second);
        }
    }
    cout << res;
    return 0;
}

2、线段树解法(树状数组也可)

首先我们看式子是 max{vi,vj}×|xi−xj| ,那么我们可以先按照vi把所有牛排序,这样我们就可以不用算max了,如果从小到大排序,那就是vj*|xi−xj| ,如果从大到小排序,就是**vi |xi−xj|* 。

然后我们看|xi−xj|,如果当前的 xi<xj ,那就是xj-xi;反之是xi-xj。这个值是根据当前两个数的关系来的。

处理他我用的是线段树,因为x的值范围是1≤xi≤3×10^4,那我们就开个子节点为3×10^4的线段树,初始都为0,那么小于xi的点,就是在区间1xi这一部分,对应的大于xi的点在区间xi3*10^4这段区间,我们只要算一下这两段的区间和,再根据区间里点的数目,就可以很快的算出这个牛和其它牛的音量之和,然后根据当前xi的值把这个点插入线段树中。为了方便我是将牛先按照vi升序排序,这样确保后面的牛的vi大于之前的vi。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 4e4;
PII f[4 * N];

bool cmp(PII a, PII b)
{
    return a.first < b.first;
}

void add(int k, int l, int r, int x)
{
    if (l == r)
    {
        f[k].first += x;
        f[k].second++;
        return ;
    }
    int m = (l + r) / 2;
    if (x <= m)add(k + k, l, m, x);
    else add(k + k + 1, m + 1, r, x);
    f[k].first = f[k + k].first + f[k + k + 1].first;
    f[k].second = f[k + k].second + f[k + k + 1].second;
}

PII calc(int k, int l, int r, int x, int y)
{
    if (l == x && r == y)
    {
        return f[k];
    }
    int m = (l + r) / 2;
    if (y <= m)return calc(k + k, l, m, x, y);
    else
        if (x > m)return calc(k + k + 1, m + 1, r, x, y);
        else
        {
            PII t;
            auto a = calc(k + k, l, m, x, m);
            auto b = calc(k + k + 1, m + 1, r, m + 1, y);
            t.first = a.first + b.first;
            t.second = a.second + b.second;
            return t;
        }
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    cin >> n;
    vector<PII>v(n);
    ll res = 0, mx = 0;
    for (int i = 0; i < n; i++)cin >> v[i].first >> v[i].second, mx = max(mx, v[i].second);
    sort(v.begin(), v.end(), cmp);

    for (int i = 0; i < n; i++)
    {
        auto a = calc(1, 1, mx, 1, v[i].second);
        auto b = calc(1, 1, mx, v[i].second, mx);
        res += v[i].first * (a.second * v[i].second - a.first);
        res += v[i].first * (b.first - b.second * v[i].second);
        add(1, 1, mx, v[i].second);
    }
    cout << res << endl;
    return 0;
}