Luogu2345 奶牛集会(树状数组)

题目背景

MooFest, 2004 Open

题目描述

约翰的 \(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\))

输出格式

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

输入输出样例

输入 #1
4
3 1
2 5
2 6
4 3
输出 #1
57
————————————————————————————————————
音量的计算公式 \(max[Vi,Vj]×|Xi?Xj|\) 看起来很友好,

由于奶牛两两之间都会发出声音,很容易想到先将奶牛按 \(Vi\) 升序排序,之后每遍历到一只奶牛,就计算这只奶牛与此前出现的所有奶牛发出的音量,统计进答案中即可。

这样我们需要求的就是当前奶牛与此前出现的所有奶牛的距离之和,即 \(\sum_{j=1}^{i-1}dis(i,j)\)

上面的这个式子是 \(O(N^2)\) 的,而我们需要在 \(O(logn)\) 的时间内解决,所以可以使用支持单点修改和区间查询的树状数组优化,

这里使用了两个树状数组,分别存储了奶牛的个数奶牛的坐标和(即到原点的距离和)

接下里我们把坐标小于当前奶牛和坐标大于当前奶牛的分开处理,具体计算公式请见代码。

最后别忘了把这个值乘上当前奶牛的 \(Vi\)再 统计进答案,之后还要把当前奶牛的数值加入两个树状数组中。

PS:还要开\(long long\)。

#include <bits/stdc++.h>
#define FOR(i,s,t) for (ll (i)=(s);(i)<=(t);(i)++)
#define lowbit(x) ((x)&(-x))
#define ll long long
#define MAXN 20007
#define MAXX 20007
using namespace std;
struct cow { ll v,x; }p[MAXN];
ll c1[MAXN],c2[MAXN],n,ans=0;
inline bool cmp(const cow &A,const cow &B) { return A.v<B.v; }
inline void add(ll x) { for (ll i=x;i<MAXX;i+=lowbit(i)) c1[i]++,c2[i]+=x; }
inline ll q1(ll x) {
    ll ret=0;
    for (ll i=x;i>=1;i-=lowbit(i)) ret+=c1[i];
    return ret;
}
inline ll q2(ll x) {
    ll ret=0;
    for (ll i=x;i>=1;i-=lowbit(i)) ret+=c2[i];
    return ret;
}
inline ll read() {
    ll X=0,w=0; char ch=0;
    while (!isdigit(ch)) w|=ch=='-',ch=getchar();
    while (isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int main() {
    memset(c1,0,sizeof(c1));
    memset(c2,0,sizeof(c2));
    n=read(); FOR(i,1,n) p[i].v=read(),p[i].x=read();
    sort(p+1,p+n+1,cmp);
    FOR(i,1,n) {
        ll amt1=q1(p[i].x-1),dis1=amt1*p[i].x-q2(p[i].x-1);
        ll amt2=q1(MAXX-1)-q1(p[i].x),dis2=q2(MAXX-1)-q2(p[i].x-1)-amt2*p[i].x;
        ans+=(dis1+dis2)*p[i].v,add(p[i].x);
    }
    printf("%lld",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/zhwer/p/12240000.html

时间: 2024-07-31 20:29:35

Luogu2345 奶牛集会(树状数组)的相关文章

LUOGU P2344 奶牛抗议 (树状数组优化dp)

传送门 解题思路 树状数组优化dp,f[i]表示前i个奶牛的分组的个数,那么很容易得出$f[i]=\sum\limits_{1\leq j\leq i}f[j-1]*(sum[i]\ge sum[j-1])$,但是这样的时间复杂度是$O(n^2)?$,所以考虑优化,发现必须满足$sum[i]\ge sum[j-1]?$才能进行转移,那么直接离散化后用树状数组维护一个前缀和即可. #include<iostream> #include<cstdio> #include<cstr

奶牛抗议 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]\)的所有和,这就可以用一个树状数组优化了,在树状数组维护下标为

bzoj 1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛【dp+树状数组+hash】

最长上升子序列.虽然数据可以直接n方但是另写了个nlogn的 转移:f[i]=max(f[j]+1)(a[j]<a[i]) O(n^2) #include<iostream> #include<cstdio> using namespace std; const int N=5005; int n,a[N],f[N],ans; int read() { int r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(

POJ 1990 MooFest(树状数组)

                                                                    MooFest Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 7077   Accepted: 3181 Description Every year, Farmer John's N (1 <= N <= 20,000) cows attend "MooFest"

【bzoj4756】[Usaco2017 Jan]Promotion Counting 离散化+树状数组

原文地址:http://www.cnblogs.com/GXZlegend/p/6832263.html 题目描述 The cows have once again tried to form a startup company, failing to remember from past experience that cows make terrible managers!The cows, conveniently numbered 1-N1-N (1≤N≤100,000), organi

bzoj4397【Usaco2015 Dec】Breed Counting(前缀和、树状数组)

题目描述 Farmer John's N cows, conveniently numbered 1…N, are all standing in a row (they seem to do so often that it now takes very little prompting from Farmer John to line them up). Each cow has a breed ID: 1 for Holsteins, 2 for Guernseys, and 3 for

HDU2838 Cow Sorting【树状数组】【逆序数】

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2838 题目大意: 有N头奶牛排成一排.每头奶牛都有一个唯一的"坏脾气"值.坏脾气的范围为1~100000.现在将 奶牛重新排序,使奶牛按照坏脾气增加的顺序排列.所有的奶牛都可以相互交换位置.但是交换脾 气值为X,Y的两头奶牛,需要的时间是X+Y.现在问:将奶牛重新排列需要的最短时间是多少. 思路: 这道题就是给你一个N个元素的序列,求这个序列中所有逆序数的和.所以,对于值为a的第i个元素

POJ 2481 树状数组 区间覆盖(POJ2352 Stars 的变形题)(线段化点)

0)学会将题目情景转化为自己熟悉的结构或模型. 题目大意: 每个奶牛有自己的一个区间,求每个奶牛的区间所覆盖的子区间个数(注意,真子集,相等的不算),按照输入的顺序输出. 转化: 要学会将题目情景转化为自己熟悉的模型或结构上.把每个区间的左端x值作为点的x坐标,右端x值作为点的y坐标,就可以把所有区间转化为一个二维坐标图上的点集,而此时每个点左上方的点(同Stars那道题目一样不包括自身)的个数,就是每个区间所覆盖的子区间的个数(对应题目要求,这里或许可以再变形). 同POJ2481 Stars

[BZOJ4756][Usaco2017 Jan]Promotion Counting 树状数组

4756: [Usaco2017 Jan]Promotion Counting Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 305  Solved: 217[Submit][Status][Discuss] Description The cows have once again tried to form a startup company, failing to remember from past experience t hat cow