每日一题-acwing小朋友排队(树状数组)
发布日期:2021-05-07 03:06:08 浏览次数:22 分类:精选文章

本文共 1044 字,大约阅读时间需要 3 分钟。

在这里插入图片描述

考虑用树状数组求解,简单的暴力会超时。

大概思路:
每个数会和前面比它大的数交换,会和后面比它小的数交换,所以每个数交换的总次数为前面比这个数大的数的个数+后面比这个数小的个数,下面的代码用b[i]维护这个个数和。

如何求呢?

用树状数组保存每个数出现的次数。

第一次正向遍历,每次将数据出现的次数加入到树状数组中,并更新b[i],更新的值为当前遍历的个数减去小于a[i](当前数)的个数。
然后清空树状数组。
第二次逆向遍历,刚好可以找后面比a[i]小的数的个数,也是每次更新b[i]。
最后对整个b[i]进行等差数列求和的计算。

#include
using namespace std;typedef long long ll;const int maxn = 1e6+5;ll a[maxn],b[maxn];ll tr[maxn];int n;void update(int a,int b){ for(int i=a;i<=maxn;i+= (i&-i) ) tr[i] += b;}ll query(int x){ ll res = 0; for(int i=x;i;i -= (i&-i)) res += tr[i]; return res;}int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) { update(a[i],1); b[i] += i - query(a[i]);//比当前数大的个数 // cout<
<<'\n'; } memset(tr,0,sizeof(tr)); for(int i=n;i>=1;i--) { update(a[i],1); b[i] += query(a[i]-1);//比当前数小的个数 // cout<
<<'\n'; } ll ans = 0; for(int i=1;i<=n;i++) { ans += b[i]*(b[i]+1)/2; } cout<
<<'\n'; return 0;}
上一篇:每日一题-acwing 完全二叉树的权值
下一篇:每日一题-区区区间间间(单调栈的应用)

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2025年03月25日 00时38分40秒