1. 程式人生 > >Codeforces Round #510 (Div. 2) D. Petya and Array(樹狀數組)

Codeforces Round #510 (Div. 2) D. Petya and Array(樹狀數組)

題解 class 就是 不同的 and std tps query col

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了,然後查詢前面小於等於

它減去t的數有多少,最後用i減去就可以了。

從後往前的話,如若當前是第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(樹狀數組)