BZOJ4994: [Usaco2017 Feb]Why Did the Cow Cross the Road III 树状数组

Description

给定长度为2N的序列,1~N各处现过2次,i第一次出现位置记为ai,第二次记为bi,求满足ai<aj<bi<bj的对数

Input

 

Output

 

Sample Input

4
3
2
4
4
1
3
2
1

Sample Output

3

HINT

N<=100000

Solution

套路题

显然这种题可以排序掉第一次,然后用树状数组解第二次,但是比较麻烦,一时没有想出来,其实也可以的

当时就再想了想,其实对于每个$i$,对于答案有贡献的显然就是它第一次出现之后,且还没有出现第二次的数,所以可以更方便的去维护

第一次出现就把出现的位置保存下来顺便+1

然后第二次出现就把这个数删掉,它不会对其他答案产生贡献了,这个数对其他数的贡献为$sum(i)-sum(last[x])$($last[x]$表示数$x$第一次出现的位置)

所以就拿树状数组维护一下就好了

#include <bits/stdc++.h> 

using namespace std ;

#define ll long long

int n , c[ 200010 ];
int last[ 100010 ] ;

int lowbit( int x ) {
    return x & -x ;
}

void add( int x , int val ) {
    for( int i = x ; i <= 2 * n ; i += lowbit( i ) ) 
        c[ i ] += val ;
}

int query( int x ) {
    int ans = 0 ;
    for( int i = x ; i ; i -= lowbit( i ) ) ans += c[ i ] ;
    return ans ;
}

int main() {
    scanf( "%d" , &n ) ;
    ll ans = 0 ;
    for( int i = 1;  i <= 2*n ; i ++ ) {
        int x ;
        scanf( "%d" , &x ) ;
        if( !last[ x ] ) last[ x ] = i , add( i , 1 ) ;
        else {
            add( last[ x ] , -1 ) ;
            ans += 1ll * query( i ) - query( last[ x ] ) ;
        } 
    }
    printf( "%lld\n" , ans ) ;
    return 0 ;
}

猜你喜欢

转载自www.cnblogs.com/henry-1202/p/BZOJ4994.html