计蒜客-重获自由 树状数组+离散化

原题链接 https://www.jisuanke.com/course/1797/165800

 

题解:这是一道比较经典的树状数组的题 。

有道题是求区间均值大于k的区间数,和这道题思路差不多,我也是看来这道题的题解才搞懂这题怎么做的,具体参考

https://blog.csdn.net/scutzyz126/article/details/78040539

这道题就是求区间[l,r]的区间和小于m,翻译成前缀和就是sum[r]-sum[l-1] < m,

假定l>=1,引入sum[0] = 0,

移项后就是sum[r] < m + sum[l-1],

因为l<=r,所以l-1<r,

给一个例子,比如sum数组为0,1,-1,2,4,m=2

相当于求有多少对数,满足前面的数加上m大于后面的数,

比如sum[1]和sum[3]就满足,因为1+2 > 2,

如果暴力遍历所有数对,时间复杂度肯定是n^2,

所以需要用树状数组来统计,

因为只关心数之间大小的相对关系,不关心数的具体值,所以对所有的数进行离散化,给他们排名,

所以把原来的sum数组0,1,-1,2,4和每个数加2后的数组2,3,1,4,6加在一块排序再去重(unique)

然后就是-1,0,1,2,3,4,6,

这7个数的排名就是1到7,

最后就从右到左边遍历sum数组的5个数,每次遍历的时候会把当前数的排名所在的地方+1,比如遍历完-1这个数的时候,-1,2,4排名1,4,6的地方就加了1,遍历到1的时候,统计Sum(rank(1+2))=Sum(5),即当前排名小于等于5的数的个数,但是因为求的数不包含等于的结果,所以应该统计Sum(rank(3)+1)=Sum(6),这样就把-1,2,4这3个数中,

小于1+m的数的个数统计出来了,然后遍历一遍就算出结果了。

这题需要注意的一个小坑就是统计结果得是long long,用int只能过40%的数据

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 7e5;
ll m;
ll a[MAXN];
int n;
ll s[MAXN];
ll temp[MAXN];
ll Rank[MAXN];
ll tree[MAXN];
int Count;

int lowbit(int x) {
    return x & -x;
}
// 排名从1开始
// x处加1
void Add(int x) {
    for(int i = x;i <= Count;i += lowbit(i)) {
        tree[i] += 1;
    }
}
// 1...x的和
int Sum(int x) {
    int res = 0;
    for(int i = x;i >= 1;i -= lowbit(i)) {
        res += tree[i];
    }
    return res;
}


int main()
{
    scanf("%d%lld",&n,&m);
    for(int i = 1;i <= n;i++) {
        scanf("%lld", &a[i]);
        s[i] = s[i-1] + a[i];
        temp[i] = s[i];
   }
//    s[0]...s[n]
   for(int i = n+1;i <= 2*n+1;i++) {
       temp[i] = s[i-n-1] + m;
   }
   sort(temp,temp+2*n+2);
   Count = unique(temp,temp+2*n+2)-temp;
   for(int i = 0;i <= n;i++) {
    	int index = lower_bound(temp,temp+Count,s[i])-temp;
    	Rank[i] = index+1;
	}

   ll res = 0;
      for(int i = n;i >=0;i--) {
        ll curRank = lower_bound(temp,temp+Count,s[i]+m)-temp;
        curRank += 1;
        res += Sum(curRank-1);
        curRank = lower_bound(temp,temp+Count,s[i])-temp;
        curRank += 1;
        Add(curRank);
    }

    printf("%lld\n",res);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/lmhlmh_/article/details/88070369