树状数组
# include<iostream>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 200010;
typedef long long ll;
/*
树状数组的主要目的是利用树形结构来优化前缀和
使得前缀和的时间复杂度优化到O(logn)
所以树状数组主要涉及的两个操作就只有修改点值
以及求前缀和
这就是树状数组的大致模样
1.每个结点tr[x]保存以x为根的子树中叶结点值的和
2.每个结点覆盖的长度为lowbit(x)
3.tr[x]结点的父结点为tr[x + lowbit(x)]
4.树的深度为log2n+1
*/
int n;
int Lower[N],Greater[N];
int a[N];/*原始数据*/
int tr[N];/*树状数组*/
int lowbit(int x)
{
/*寻找点x距离其祖先的距离*/
return x & -x;
}
void add(int x,int k)
{
/*当点x出增加k时,其祖先也都增加k*/
for(int i = x;i <= n;i+=lowbit(i)) tr[i] += k;
}
int ask(int x)
{
/*求前x个数的前缀和*/
int sum = 0;
for(int i = x;i;i-=lowbit(i)) sum+=tr[i];
return sum;
}
int main(){
cin>>n;
for(int i = 1;i <= n;++i) cin>>a[i];
for(int i = 1;i <= n;++i)
{
int y = a[i];
Lower[i] = ask(y-1);/*前i个数里比y小的数的个数*/
Greater[i] = ask(n)- ask(y);/*前i个数里比y大的数的个数*/
add(y,1);/*表示y在原始数据中出现过一次*/
}
/*
此模板主要利用ACwing中 题241.楼兰图腾做演示
后续内容与题相关
*/
ll resA = 0;
ll resV = 0;
memset(tr,0,sizeof(tr));
for(int i = n;i;--i)
{
int y = a[i];
resA +=Lower[i]*(ll)ask(y-1);
resV +=Greater[i]*(ll)(ask(n)-ask(y));
add(y,1);
}
printf("%lld %lld\n",resV,resA);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】