【树状数组】【P2345】 奶牛集会
Description
约翰的头奶牛每年都会参加“哞哞大会”。哞哞大会是奶牛界的盛事。集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。它们参加活动时会聚在一起,第i 头奶牛的坐标为Xi,没有两头奶牛的坐标是相同的。奶牛们的叫声很大,第i 头和第j 头奶牛交流,会发出 的音量,其中 和 分别是第 头和第,头奶牛的听力。假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。
Input
第一行:单个整数
第二行到第 行:第 行有两个整数和。
Output
单个整数:表示所有奶牛产生的音量之和
Sample Input
4
3 1
2 5
2 6
4 3
Sample Output
57
Hint
所有数据
Solution
发现枚举每两头奶牛是一件非常傻逼的事情。所以考虑对于每对奶牛,计算每头更小(或更大)的牛的答案。
为了破除掉的干扰,可以按照升序排序,这样扫一遍数组,就可以对于每个位置只计算它之前的牛的位置差最后乘v即可。
考虑快速求出每个位置之前的x值。
对于之前的每个,共有两种,分别是大于和小于的。这样按照坐标建立树状数组可以统计他之前之后的和以及个数,可以轻松算出该位置的ans。
Code
#include<cstdio>
#include<algorithm>
#define rg register
#define ci const int
#define cl const long long int
typedef long long int ll;
namespace IO {
char buf[90];
}
template<typename T>
inline void qr(T &x) {
char ch=getchar(),lst=' ';
while(ch>'9'||ch<'0') lst=ch,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst=='-') x=-x;
}
template<typename T>
inline void write(T x,const char aft,const bool pt) {
if(x<0) x=-x,putchar('-');
int top=0;
do {
IO::buf[++top]=x%10+'0';
x/=10;
} while(x);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
}
template<typename T>
inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
template<typename T>
inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
template<typename T>
inline T mabs(const T a) {if(a<0) return -a;return a;}
template<typename T>
inline void mswap(T &a,T &b) {
T temp=a;a=b;b=temp;
}
const int maxn = 20010;
const int upceil = 20000;
struct Tree {
int cnt;ll sum;
inline Tree(int _a=0,ll _b=0) {cnt=_a,sum=_b;}
};
Tree frog[maxn];
struct M {
int v,x;
inline bool operator<(const M &_others) const {
return this->v<_others.v;
}
};
M MU[maxn];
int n;
ll ans;
inline int lowbit(ci x) {return x&((~x)+1);}
void add(ci);
Tree ask(int);
int main() {
qr(n);
for(rg int i=1;i<=n;++i) {qr(MU[i].v);qr(MU[i].x);}
std::sort(MU+1,MU+1+n);
for(rg int i=1;i<=n;++i) {
Tree _ans1=ask(MU[i].x),_ans2=ask(upceil);
ans+=(1ll*_ans1.cnt*MU[i].x-_ans1.sum+(_ans2.sum-_ans1.sum)-1ll*(_ans2.cnt-_ans1.cnt)*MU[i].x)*MU[i].v;
add(MU[i].x);
}
write(ans,'\n',true);
return 0;
}
Tree ask(int x) {
ll _sum=0;int _cnt=0;
while(x) {
_sum+=frog[x].sum;
_cnt+=frog[x].cnt;
x-=lowbit(x);
}
return Tree(_cnt,_sum);
}
void add(ci x) {
int _c=x;
while(_c<=upceil) {
frog[_c].sum+=x;
++frog[_c].cnt;
_c+=lowbit(_c);
}
}
Summary
当计算被最大值限制时,可以考虑升/降序排序一次计算该位置从而避免最大值的枚举
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具