luogu 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

输出格式

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


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int N=2e4+1;
struct E{
    int v,x;
}e[N];
int n;
bool cmp(E t1,E t2){
    return t1.v<t2.v;
}
ll c1[N],c2[N];
void add1(int x,int y)
{
    for(;x<=N;x+=x&(-x))
    c1[x]+=y;
}
ll num1(int x)
{
    int ans=0;
    for(;x;x-=x&(-x))ans+=c1[x];
    return ans;
}
void add2(int x,int y)
{
    for(;x<=N;x+=x&(-x))
    c2[x]+=y;
}
ll num2(int x)
{
    int ans=0;
    for(;x;x-=x&(-x))ans+=c2[x];
    return ans;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    scanf("%d%d",&e[i].v,&e[i].x);
    sort(e+1,e+1+n,cmp);
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        ll p1=num1(e[i].x),p2=num2(e[i].x);
        ans+=e[i].v*abs(e[i].x*p1-p2);
        p1=num1(N)-p1;p2=num2(N)-p2;
        ans+=e[i].v*abs(e[i].x*p1-p2);
        add1(e[i].x,1);
        add2(e[i].x,e[i].x);
    }
    cout<<ans<<endl;
}

原文地址:https://www.cnblogs.com/naruto-mzx/p/11854695.html

时间: 2024-08-17 16:10:31

luogu P2345 奶牛集会 |排序+树状数组的相关文章

luogu P2345 奶牛集会

二次联通门 : luogu P2345 奶牛集会 /* luogu P2345 奶牛集会 权值线段树 以坐标为下标, 坐标为值建立线段树 对奶牛按听力由小到大排序 对于要查的牛 每次第i次放入奶牛起作用的v就是vi: 每次ans+=(xi*sum-sumxl)*vi+(sumxr-xi*sum)*vi */ #include <algorithm> #include <cstdio> #define Max 400003 void read (int &now) { now

奶牛抗议 DP 树状数组

奶牛抗议 DP 树状数组 USACO的题太猛了 容易想到\(DP\),设\(f[i]\)表示为在第\(i\)位时方案数,转移方程: \[ f[i]=\sum f[j]\;(j< i,sum[i]-sum[j]\ge0) \] \(O(n^2)\)过不了,考虑优化 移项得: \[ f[i]=\sum f[j]\;(j< i,sum[i]\ge sum[j]) \] 这时候我们发现相当于求在\(i\)前面并且前缀和小于\(sum[i]\)的所有和,这就可以用一个树状数组优化了,在树状数组维护下标为

Hdu5032 极角排序+树状数组

题目链接 思路:参考了题解.对询问进行极角排序,然后用树状数组维护一下前缀和即可. /* ID: onlyazh1 LANG: C++ TASK: test */ #include<bits/stdc++.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 typedef long long ll; const int maxn=1010; const int maxm=10

HDU Always Cook Mushroom (极角排序+树状数组)

Problem Description Matt has a company, Always Cook Mushroom (ACM), which produces high-quality mushrooms. ACM has a large field to grow their mushrooms. The field can be considered as a 1000 * 1000 grid where mushrooms are grown in grid points numbe

ACM--归并排序&amp;&amp;树状数组--nyoj 117--求逆序数

南阳oj题目地址:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=117 求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数是多少. 比如 1 3 2 的逆序数就是1. 输入 第一行输入一个整数T表示测试数据的组

hdu--4911--归并排序||树状数组

发现一个小小的 逆序数里真的藏了好多东西啊=-= 解决这题 你需要知道一点... 对于一串给定的数字 我随便写一串吧.. index:   0 1 2 3 4 value: 4 8 7 5 6    这时候 总的逆序对数是  3+2=5   假如我们只能进行相邻元素的交换 这最好情况是什么呢? 那肯定就是假如本来 arr[x]>arr[x+1] 那这样是形成一个逆序数的吧 我们将它进行交换 这样就少了一个逆序数对是吧... 但是 对于其它位置的元素是没有影响的对吧 所以 我们需要的最小次数呢 就

luogu P3368 【模板】树状数组 2

P3368 [模板]树状数组 2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含2或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x 含义:输出第x个数的值 输出格式: 输出

Luogu P3374 【模板】树状数组 1[单点修改-区间查询]

P3374 [模板]树状数组 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x k 含义:将第x个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和 输出格式: 输出包

Codeforces 101B Buses 排序+树状数组

题目链接:点击打开链接 当转移[l,r] 区间时, 若[0, r-1] 这里的区间都已经转移完毕时是最优的,所以按右端点升序,同理右端点相同时左端点升序,然后树状数组维护一下前缀和. #include <vector> #include <iostream> #include <algorithm> #include <string.h> #include <stdio.h> using namespace std; #define N 1000