Codeforces Round #510 (Div. 2) D. Petya and Array(樹狀數組)
阿新 • • 發佈:2019-01-20
題解 class 就是 不同的 and std tps query col 它減去t的數有多少,最後用i減去就可以了。
D. Petya and Array
題目鏈接:https://codeforces.com/contest/1042/problem/D
題意:
給出n個數,問一共有多少個區間,滿足區間和小於t。
題解:
假設目前區間右端點為r,左端點為l,那麽由前綴和可得知:sumr-suml-1<t,然後我們再邊個形:sumr<t+suml-1,根據這個我們可以發現這有點類似於逆序對。
然後我們就可以用求解逆序對問題的解法來解這個問題了,這裏不同的就是每次前面的加上t大於當前這個數即為一對逆序對。
我用的樹狀數組來做的,用樹狀數組用兩種枚舉方式,一種是從前往後,另一種是從後往前。
從前往後的話,如若當前是第i個位置,那麽首先要保證前面i-1個數都update了,然後查詢前面小於等於
從後往前的話,如若當前是第i個位置,那麽從i到最後一個位置都應插入進去,之後查詢有多少個小於它加上r就行了。
這個題裏面0也應該考慮進去,表示從1到x的這個區間。
代碼如下(包含兩種方式):
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+5; ll n,t; ll a[N],sum[N],c[N]; ll lowbit(ll x){ return x&(-x); }void upd(ll x,ll b){ for(;x<=N-2;x+=lowbit(x)) c[x]+=b; } ll query(ll x){ ll ans = 0; for(;x>0;x-=lowbit(x)) ans+=c[x]; return ans ; } int main(){ scanf("%I64d%I64d",&n,&t); ll ans=0; for(int i=1;i<=n;i++){ scanf("%I64d",&a[i]); sum[i]=sum[i-1]+a[i]; a[i]=sum[i]; } sort(sum,sum+n+1); /*for(int i=n;i>=0;i--){ int pos1 = lower_bound(sum,sum+n+1,a[i]+t)-sum; int pos2 = lower_bound(sum,sum+n+1,a[i])-sum+1; ans+=query(pos1); //printf("%d\n",pos1); upd(pos2,1); }*/ for(int i=1;i<=n;i++){ int pos1 = lower_bound(sum,sum+n+1,a[i-1])-sum+1; int pos2 = upper_bound(sum,sum+n+1,a[i]-t)-sum; upd(pos1,1); ans+=i-query(pos2); } cout<<ans; return 0; }
Codeforces Round #510 (Div. 2) D. Petya and Array(樹狀數組)