POJ 3468 A Simple Problem with Integers ( Splay )

题意 : n个数,成段更新,区间求和 。

思路 : 线段树可以做,用splay做感觉好辛苦 ... 吃力不讨好 ... 纯粹就是当做熟悉splay用的

要用splay访问一个区间[L,R], 我们只要把 L-1 splay 到根 , 然后把 R + 1 splay 到根的右子树

那么 根的右子树的左子树就是[ L , R ] 这个区间了


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

#define MAXN 100005
#define INF 0x3f3f3f3f
#define keyNode ( ch[ch[root][1]][0] ) 
#define ls(x) ( ch[x][0] ) 
#define rs(x) ( ch[x][1] ) 
typedef long long LL ;
int n , m ;

struct Splay{
	int tot ;
	int ch[MAXN][2] ;
	int pre[MAXN] ;
	int sz[MAXN] ;
	LL sum[MAXN] ;
	LL val[MAXN] ;
	LL add[MAXN] ;
	LL a[MAXN] ;
	int root ;

	// 旋转
	void Rotate( int x , int op ) {
		int y = pre[x] ;
		push_down( y ) ;
		push_down( x ) ;
		if( pre[y] ) {
			ch[pre[y]][ch[pre[y]][1] == y ] = x ;
		}
		pre[x] = pre[y] ;
		pre[y] = x ;
		ch[y][op] = ch[x][op^1] ;
		if( pre[ch[x][op^1]] )
			pre[ch[x][op^1]] = y ;
		ch[x][op^1] = y ;
		push_up(y) ; 
	}

	// 伸展
	void splay( int x , int goal ) {
		push_down( x ) ;
		while( pre[x] != goal ) {
			int y = pre[x] ;
			if( pre[y] == goal ) {
				Rotate( x , ch[y][1] == x ) ;
			}else{
				int y = pre[x] ;
				int op = rs(y) == x ;
				if( ch[pre[y]][op] == y ) {
					Rotate( y , op ) ;
					Rotate( x , op ) ;
				}else{
					Rotate( x , op ) ;
					Rotate( x , op ^ 1 ) ;
				}
			}
		}
		push_up( x ) ;
		if( goal == 0 ) root = x ;
	}

	// 把第k个伸展至goal下
	void RotateTo( int k , int goal ) {
		int x = root ;
		push_down( x ) ;
		while( sz[ls(x)] != k ) {
			if( k < sz[ls(x)] ) {
				x = ls(x) ;
			}else{
				k -= sz[ls(x)] + 1 ;
				x = rs(x) ;
			}
			push_down( x ) ;
		}
		splay( x , goal ) ;
	}

	// 创建一个结点
	void makenode( int &x , int fa , LL v ) {
		x = tot ++ ;
		pre[x] = fa ;
		ls(x) = rs(x) = 0 ;
		sz[x] = 1 ;
		sum[x] = val[x] = v ;
		add[x] = 0 ;
	}

	// 子节点信息向上传
	void push_up( int x ) {
		sz[x] = sz[ls(x)] + sz[rs(x)] + 1 ;
		sum[x] = add[x] + val[x] + sum[ls(x)] + sum[rs(x)] ;
	}

	// 父节点信息向下传
	void push_down( int x ) {
		if( add[x] ) {
			val[x] += add[x] ;
			add[ls(x)] += add[x] ;
			add[rs(x)] += add[x] ;
			sum[ls(x)] += sz[ls(x)] * add[x] ;
			sum[rs(x)] += sz[rs(x)] * add[x] ;
			add[x] = 0 ;
		}
	}

	// 创建区间
	void build( int l , int r , int & x , int fa ) {
		if( l > r ) return ;
		int m = ( l + r ) >> 1 ;
		makenode( x , fa , a[m] ) ;
		build( l , m - 1 , ls(x) , x ) ;
		build( m + 1 , r , rs(x) , x ) ;
		push_up( x ) ;
	}

	// 查询区间信息
	LL query( int l , int r ) {
		RotateTo( l - 1 , 0 ) ;
		RotateTo( r + 1 , root ) ;
		return sum[keyNode] ;
	}

	// 更新区间信息
	LL update( int l , int r , int c ) {
		RotateTo( l - 1 , 0 ) ;
		RotateTo( r + 1 , root ) ;
		add[keyNode] += c ;
		sum[keyNode] += sz[keyNode] * c ;
		LL ans = sum[keyNode] ;
		splay( keyNode , 0 ) ;
		return ans ;
	}

	// 初始化splay
	void init(){
		//=============== 初始化边界 ================
		tot = 1 ;
		makenode( root , 0 , 0 ) ;
		makenode( rs(root) , root , 0 ) ;
		sz[root] ++ ;
		//=============== 初始化区间 ================
		for( int i = 1 ; i <= n ; i ++ ) {
			scanf( "%lld" , &a[i] ) ;
		}
		build( 1 , n , keyNode , rs(root) ) ;
		push_up( rs(root) ) ;
		push_up( root ) ;
	}

}s;

int main(){
	while( scanf( "%d%d" , &n , &m ) != EOF ) {
		s.init() ;
		while( m -- ) {
			char op[10] ;
			scanf( "%s" , op ) ;
			if( op[0] == 'Q' ) {
				int l , r ;
				scanf( "%d%d" , &l ,&r ) ;
				printf( "%lld\n" , s.query( l , r ) ) ;
			}else{
				int l , r , c ;
				scanf( "%d%d%d" , &l , &r , &c ) ;
				s.update( l , r , c ) ;
			}
		}
	}
	return 0 ;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值