【HDU】5140 Hun Gui Wei Company 主席树

传送门:【HDU】5140 Hun Gui Wei Company


题目分析:一般情况下,区间很大的话,第一反应就是离散,我也不例外,但是本题的区间很大!并且重要的是强制在线让人不能离散!但是这样就能阻挡我们AC的步伐吗?当然不能!注意到,我们将数从小到大排好序,将此时的下标作为主席树的下标,然后我们怎么为那么大的查询范围找到对应的区间呢?显然可以用二分啊~直接二分出查询的区间就好辣,因为此时数组有序满足二分的性质。

这个就是本题的技术难题。

而每次在(x,y)点插入一个权值为c的点,查询矩阵【x1,x2】【y1,y2】内所有点的权值和我们可以用主席树来做,即在下标为x的主席树上下标为y的位置插入点,查询下标【x1,x2】内主席树上【y1,y2】区间内点的和,这个比较基础,我就不熬述了。


PS:

1.注意处理好左右两边界。

2.注意数组大小。

3.区间是先加上或减去ans,然后如果左端点大于右端点就交换。


代码如下:


#include <cstdio>
#include <cstring>
#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 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 )

const int MAXN = 100005 ;

struct Node {
	Node* c[2] ;
	LL sum ;
} ;

struct People {
	int s , l , a ;
	People () {}
	People ( int s , int l , int a ) : s ( s ) , l ( l ) , a ( a ) {}
	bool operator < ( const People& t ) const {
		return l < t.l ;
	}
} ;

People p[MAXN] ;
Node pool[MAXN * 40] ;
Node* cur ;
Node* root[MAXN] ;

int a[MAXN] ;
int b[MAXN] , cnt ;
int n , m ;

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

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

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

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

void build ( Node* &o , int l , int r ) {
	o = cur ++ ;
	o->sum = 0 ;
	if ( l == r ) return ;
	int m = mid ;
	build ( o->c[0] , l , m ) ;
	build ( o->c[1] , m + 1 , r ) ;
}

void insert ( Node* old , Node* &now , int x , int v , int l , int r ) {
	now = cur ++ ;
	if ( l == r ) {
		now->sum = old->sum + v ;
		return ;
	}
	int m = mid ;
	if ( x <= m ) {
		now->c[1] = old->c[1] ;
		insert ( old->c[0] , now->c[0] , x , v , l , m ) ;
	} else {
		now->c[0] = old->c[0] ;
		insert ( old->c[1] , now->c[1] , x , v , m + 1 , r ) ;
	}
	now->sum = now->c[0]->sum + now->c[1]->sum ;
}

LL query ( Node* old , Node* now , int x , int l , int r ) {
	LL ans = 0 ;
	while ( l < r ) {
		int m = mid ;
		if ( x <= m ) {
			r = m ;
			old = old->c[0] ;
			now = now->c[0] ;
		} else {
			ans += now->c[0]->sum - old->c[0]->sum ;
			old = old->c[1] ;
			now = now->c[1] ;
			l = m + 1 ;
		}
	}
	ans += now->sum - old->sum ;
	return ans ;
}

void scanf ( int& x , char c = 0 ) {
	while ( ( c = getchar () ) < '0' ) ;
	x = c - '0' ;
	while ( ( c = getchar () ) >= '0' ) x = x * 10 + c - '0' ;
}

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

void solve () {
	LL ll , hl , la , ha ;
	LL ans = 0 ;
	cur = pool ;
	For ( i , 1 , n ) {
		scanf ( p[i].s ) ;
		scanf ( p[i].l ) ;
		scanf ( p[i].a ) ;
		//scanf ( "%d%d%d" , &p[i].s , &p[i].l , &p[i].a ) ;
		b[i] = p[i].a ;
	}
	p[n + 1] = People ( 0 , -1 , -1 ) ;
	p[n + 2] = People ( 0 , 1000000001 , 1000000001 ) ;
	b[n + 1] = -1 ;
	b[n + 2] = 1000000001 ;
	n += 2 ;
	sort ( p + 1 , p + n + 1 ) ;
	For ( i , 1 , n ) a[i] = p[i].l ;
	cnt = unique ( n ) ;
	build ( root[0] , 1 , cnt ) ;
	For ( i , 1 , n ) insert ( root[i - 1] , root[i] , hash ( p[i].a ) , p[i].s , 1 , cnt ) ;
	scanf ( "%d" , &m ) ;
	while ( m -- ) {
		scanf ( ll ) ;
		scanf ( hl ) ;
		scanf ( la ) ;
		scanf ( ha ) ;
		//canf ( "%I64d%I64d%I64d%I64d" , &ll , &hl , &la , &ha ) ;
		ll += ans ;
		hl -= ans ;
		la += ans ;
		ha -= ans ;
		if ( ll > hl ) swap ( ll , hl ) ;
		if ( la > ha ) swap ( la , ha ) ;
		ll = max ( -1LL , ll ) ;
		la = max ( -1LL , la ) ;
		hl = min ( 1000000001LL , hl ) ;
		ha = min ( 1000000001LL , ha ) ;
		ll = lower_bound ( ll , a , 1 , n ) ;
		hl = upper_bound ( hl , a , 1 , n ) ;
		la = lower_bound ( la , b , 1 , cnt ) ;
		ha = upper_bound ( ha , b , 1 , cnt ) ;
		//printf ( "%I64d %I64d %I64d %I64d\n" , ll , hl , la , ha ) ;
		ans = query ( root[ll - 1] , root[hl] , ha , 1 , cnt ) - query ( root[ll - 1] , root[hl] , la - 1 , 1 , cnt ) ;
		printf ( "%I64d\n" , ans ) ;
	}
}

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值