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
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 ; }