1. 程式人生 > >樹狀陣列 簡單題 cf 961E

樹狀陣列 簡單題 cf 961E

    題目連結 : https://codeforces.com/problemset/problem/961/E

        

One day Polycarp decided to rewatch his absolute favourite episode of well-known TV series "Tufurama". He was pretty surprised when he got results only for season 7 episode 3 with his search query of "Watch Tufurama season 3 episode 7 online full hd free". This got Polycarp confused — what if he decides to rewatch the entire series someday and won't be able to find the right episodes to watch? Polycarp now wants to count the number of times he will be forced to search for an episode using some different method.

TV series have n seasons (numbered 1 through n), the i-th season has ai episodes (numbered 1 through ai). Polycarp thinks that if for some pair of integers x and y (x < y) exist both season x episode y and season y episode x then one of these search queries will include the wrong results. Help Polycarp to calculate the number of such pairs!

Input

The first line contains one integer n (1  ≤ n  ≤  2·105) — the number of seasons.

The second line contains n integers separated by space a1, a2, ..., an (1 ≤ ai ≤ 109) — number of episodes in each season.

Output

Print one integer — the number of pairs x and y (x < y

) such that there exist both season x episode y and season y episode x.

Examples Input Copy
5 1 2 3 4 5
Output Copy
0
Input Copy
3 8 12 7
Output Copy
3
Input Copy
3 3 2 1
Output Copy
2
Note

Possible pairs in the second example:

  1. x = 1, y = 2 (season 1 episode 2 season 2 episode 1);
  2. x = 2, y = 3 (season 2 episode 3 season 3 episode 2);
  3. x = 1, y = 3 (season 1 episode 3 season 3 episode 1).

In the third example:

  1. x = 1, y = 2 (season 1 episode 2 season 2 episode 1);
  2. x = 1, y = 3 (season 1 episode 3 season 3 episode 1).

 

 

      題目大意  : (首先這個題有一個電視劇) 輸入n (代表一共有 多少季)之後有n個數每個數 代表這季有多少集,如果 x 季 y集 和 y 季 x集能

                同時被找到就說明有一個錯誤。例如  n = 2   a1=2  a2=3 有 1 季 2 集 和 2 季 1 集 說明有一個錯誤則輸出 1 .

      思路 : 保證 ax>=y x<y ay>=x 這三個條件,如果只是前兩個的話樹狀陣列完全可以滿足,但如果加上第三個條件的話,樹狀陣列沒法滿足

          所以想到先把第三個條件預處理出來存到vector中,然後依次解決.vector中壓入v [ min( i-1, a [ i ] ) ] . push_back( i ),為什麼要這麼

          寫呢首先a[ i ] =min  ( a[ i ] , n  ),這個不難理解因為如果a [ i ]  > n 的話比n 大的沒有意義因為最多就到n季。然後為什麼vector中要

          以 min  ( i - 1 , a [ i ] ) 為一維呢,這裡是指當前 i 能到達的極限,極限有兩種情況{ 1.如果ai大的話可以通過之後的 i 來查詢當前剩

          餘的ai,2.如果 i 大的話說明當前這個值最多能達到ai(可以手動推一下) } 那為什麼是 i -1 呢?因為如果 i = 5 , a5=3 的話 i 要從 4

          開始查因為和自己查沒有意義還會出錯.  

          這裡要壓入 i 是為了之後找 ax>=i 因為在樹狀陣列求逆序數是 sum(MAX_N)-sum ( ai ) , 這個是求ax>ai,而我們要求的是 ax> = i  

          所以我們變成了 sum(MAX_N)-sum(i),這裡 x < i 一直成立.

          還有就是ai的範圍是1e9 太大了,在這道題中當 ai>n 和ai=n 是等價的,因為一共就n那麼大,如果ai比n大的話找不到更大的和ai對應

          所以是等價的.

 

#include<bits/stdc++.h>
using namespace std;
int x[200020];
int szsz[200020];
int m,n;
vector <int> vic[200020];
int lowbit(int a){
    return a&(-a);
}
void add(int a){
    for(int i=a;i<=200015;i+=lowbit(i)){
        szsz[i]+=1;
    }
}
int qiuhe(int a){
    int ans=0;
    for(int i=a;i>=1;i-=lowbit(i)){
        ans+=szsz[i];
    }
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&x[i]);
        x[i]=min(n,x[i]);
        vic[min(i-1,x[i])].push_back(i);
    }
    memset(szsz,0,sizeof(szsz));
    long long sum=0;
    for(int i=1;i<=n;i++){
        add(x[i]);
        for(int j=0;j<vic[i].size();j++){
            sum+=qiuhe(n)-qiuhe(vic[i][j]-1);
        }
    }
    printf("%lld\n",sum);
    return 0;
}