求区间均值大于K区间数---树状数组

来源:互联网 发布:seo网络推广职业规划 编辑:程序博客网 时间:2024/06/05 17:27

http://arc075.contest.atcoder.jp/tasks/arc075_c

题意:

给你一个序列和一个数k,求有多少对l,r,使得a[l]+a[l+1]+...+a[r]的算术平均数大于等于k

  • 1≤N≤2×10^5
  • 1≤K≤10^9
  • 1≤ai≤10^9

思路:

首先对于所有数减去k,这样就不用除(r-l+1), 然后我们发现所求的就是有多少对l,r,使得sum[r]-sum[l-1] >= 0, sum是减去k之后的序列的前缀和

用树状数组对sum求有多少个顺序对,多加一个0这个数,代表从sum[r]-sum[0]对答案的贡献。

由于sum[i]可能很大,所以需要离散化。


#include <bits/stdc++.h>using namespace std;typedef long long ll;inline ll read(){    ll x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}const int maxn = 2e5+10;ll n,k,x,s[maxn],tree[maxn];vector<ll> v;void add(ll x){    while(x < maxn){        tree[x] += 1;        x += x&-x;    }}ll sum(ll x){    ll res = 0;    while(x > 0){        res += tree[x];        x -= x&-x;    }    return res;}int main(){    freopen("a.txt","r",stdin);        scanf("%d%d",&n,&k) ;    for(int i=1; i<=n; i++){        x = read();        x -= k;        s[i] = s[i-1]+x;    }        //把s[0]=0加进前缀和一起排序     for(int i=0; i<=n; i++)         v.push_back(s[i]);    sort(v.begin(),v.end());    v.resize(unique(v.begin(),v.end())-v.begin());//去重         //离散化     for(int i=0; i<=n; i++) s[i] = lower_bound(v.begin(),v.end(),s[i])-v.begin()+1;    ll ans = 0;        //s数组已经包含了0在内的排序序号//先统计个数,现更新     for(int i=0; i<=n; i++){        ans += sum(s[i]);        printf("before update %d  ans:%d ",s[i],ans);for(int j=0;j<=n;j++) printf("%d ",tree[j]);printf("\n");        add(s[i]);    }    cout << ans << endl;    return 0;}


原创粉丝点击