【COGS】256 [POI2001] 金矿 线段树

传送门:【COGS】256 [POI2001] 金矿


题目分析:将每个点作为一个矩阵的右下角添加这个矩阵的下边以及上边,这样本题转化成了区间加减以及求区间最大的问题。


代码如下:


#include 
#include 
#include 
#include 
using namespace std ;
 
#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 travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define CLR( a , x ) memset ( a , x , sizeof a )
#define CPY( a , x ) memcpy ( 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 root 1 , 1 , cnt
#define mid ( ( l + r ) >> 1 )

const int MAXN = 15005 ;

struct Line {
	int l , r , h , v ;
	Line () {}
	Line ( int l , int r , int h , int v ) : l ( l ) , r ( r ) , h ( h ) , v ( v ) {}
	bool operator < ( const Line& a ) const {
		return h != a.h ? h < a.h : v > a.v ;
	}
} L[MAXN << 1] ;

int a[MAXN << 1] , cnt ;
int maxv[MAXN << 3] , addv[MAXN << 3] ;
int s , w ;
int n ;

void scanf ( int& x , char c = 0 , bool flag = 0 ) {
	while ( ( c = getchar () ) != '-' && ( c < '0' || c > '9' ) ) ;
	if ( c == '-' ) flag = 1 , x = 0 ;
	else x = c - '0' ;
	while ( ( c = getchar () ) >= '0' && c <= '9' ) x = x * 10 + c - '0' ;
	if ( flag ) x = -x ;
}

int unique ( int n ) {
	int cnt = 1 ;
	sort ( a + 1 , a + n + 1 ) ;
	FOR ( i , 2 , n ) if ( a[i] != a[cnt] ) a[++ cnt] = a[i] ;
	return cnt ;
}

int search ( int x , int l , int r ) {
	while ( l < r ) {
		int m = mid ;
		if ( a[m] >= x ) r = m ;
		else l = m + 1 ;
	}
	return l ;
}

void pushdown ( int o ) {
	if ( addv[o] ) {
		addv[ls] += addv[o] ;
		addv[rs] += addv[o] ;
		maxv[ls] += addv[o] ;
		maxv[rs] += addv[o] ;
		addv[o] = 0 ;
	}
}

void update ( int L , int R , int v , int o , int l , int r ) {
	if ( L <= l && r <= R ) {
		maxv[o] += v ;
		addv[o] += v ;
		return ;
	}
	int m = mid ;
	pushdown ( o ) ;
	if ( L <= m ) update ( L , R , v , lson ) ;
	if ( m <  R ) update ( L , R , v , rson ) ;
	maxv[o] = max ( maxv[ls] , maxv[rs] ) ;
}

void solve () {
	int x , y ;
	scanf ( s ) ;
	scanf ( w ) ;
	scanf ( n ) ;
	cnt = 0 ;
	CLR ( addv , 0 ) ;
	CLR ( maxv , 0 ) ;
	REP ( i , 0 , n ) {
		scanf ( "%d%d" , &x , &y ) ;
		a[++ cnt] = x ;
		a[++ cnt] = x + s ;
		L[i << 1] = Line ( x , x + s , y , 1 ) ;
		L[i << 1 | 1] = Line ( x , x + s , y + w , -1 ) ;
	}
	cnt = unique ( cnt ) ;
	n <<= 1 ;
	sort ( L , L + n ) ;
	int ans = 0 ;
	REP ( i , 0 , n ) {
		int l = search ( L[i].l , 1 , cnt ) ;
		int r = search ( L[i].r , 1 , cnt ) ;
		update ( l , r , L[i].v , root ) ;
		ans = max ( ans , maxv[1] ) ;
	}
	printf ( "%d\n" , ans ) ;
}

int main () {
	freopen ( "kop.in" , "r" , stdin ) ;
	freopen ( "kop.out" , "w" , stdout ) ;
	solve () ;
	return 0 ;
}


你可能感兴趣的:(线段树)