树状数组

# 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;
}

posted @   empty_y  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示