【BZOJ】3289: Mato的文件管理【区间逆序对,莫队套树状数组】

传送门:【BZOJ】3289: Mato的文件管理


my code:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std ;

typedef long long LL ;

#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clrs( a , x , sizes ) memset ( a , x , sizeof ( a[0] ) * ( sizes + 1 ) )
#define clr( a , x ) memset ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define mid ( ( l + r ) >> 1 )
#define root 1 , 1 , n

const int MAXN = 500005 ;
const int SQRT = 300 ;

struct Node {
	int l , r , pos , idx ;
	bool operator < ( const Node& a ) const {
		if ( pos != a.pos ) return pos < a.pos ;
		return r < a.r ;
	}
} ;

Node q[MAXN] ;
int c[MAXN] ;
int a[MAXN] ;
int idx[MAXN] ;
int ans[MAXN] ;
int n , m ;

void add ( int x , int v ) {
	for ( int i = x ; i <= n ; i += i & -i ) c[i] += v ;
}

int sum ( int x , int ans = 0 ) {
	for ( int i = x ; i > 0 ; i -= i & -i ) ans += c[i] ;
	return ans ;
}

bool cmp ( const int& x , const int& y ) {
	return a[x] < a[y] ;
}

void solve () {
	int sqr = sqrt ( 1.2 * n ) ;
	clr ( c , 0 ) ;
	For ( i , 1 , n ) {
		scanf ( "%d" , &a[i] ) ;
		idx[i] = i ;
	}
	sort ( idx + 1 , idx + n + 1 , cmp ) ;
	For ( i , 1 , n ) a[idx[i]] = i ;
	scanf ( "%d" , &m ) ;
	rep ( i , 0 , m ) {
		scanf ( "%d%d" , &q[i].l , &q[i].r ) ;
		q[i].idx = i ;
		q[i].pos = q[i].l / sqr ;
	}
	sort ( q , q + m ) ;
	int l = 1 , r = 0 , res = 0 ;
	rep ( i , 0 , m ) {
		int L = q[i].l , R = q[i].r ;
		while ( r < R ) {
			add ( a[++ r] , 1 ) ;
			res += r - l - sum ( a[r] - 1 ) ;
		}
		while ( r > R ) {
			res -= r - l - sum ( a[r] - 1 ) ;
			add ( a[r --] , -1 ) ;
		}
		while ( l < L ) {
			res -= sum ( a[l] - 1 ) ;
			add ( a[l ++] , -1 ) ;
		}
		while ( l > L ) {
			add ( a[-- l] , 1 ) ;
			res += sum ( a[l] - 1 ) ;
		}
		ans[q[i].idx] = res ;
	}
	rep ( i , 0 , m ) printf ( "%d\n" , ans[i] ) ;
}

int main () {
	while ( ~scanf ( "%d" , &n ) ) solve () ;
	return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值