POJ 3468 区间查询区间修改 伸展树

题意:

 

n个数,有两种操作,一种是查询区间和,另一种是在区间上每一个数加上v。

 

bake爷的数组版改造成了结构体版。。

 

#include<stdio.h>
#include<string.h>
#include<vector>
#include<iostream>
#include<queue>
using namespace std;
#define ll long long
#define N 100105
#define inf 100000000
#define L(id) tree[id].ch[0]
#define R(id) tree[id].ch[1]
#define Father(id) tree[id].fa
#define Mid(x,y) ((x+y)>>1)

ll num[N];//序列
struct Node{
	ll ch[2], fa, size;
	ll val, sum, add;
}tree[N];
ll tot, root;
void Newnode(ll& id, ll fa, ll val){
	id = ++tot;
	Father(id) = fa;
	tree[id].sum = tree[id].val = val;
	tree[id].add = 0;
	tree[id].size = 1;
	L(id) = R(id) = 0;
}
void push_down(ll id){
	if(tree[id].add)
	{
		tree[id].val += tree[id].add;
		tree[L(id)].sum += tree[id].add * tree[L(id)].size;
		tree[R(id)].sum += tree[id].add * tree[R(id)].size;
		tree[L(id)].add += tree[id].add;
		tree[R(id)].add += tree[id].add;
		tree[id].add = 0;
	}
}
void push_up(ll id){
	tree[id].size = tree[L(id)].size+tree[R(id)].size +1;
	tree[id].sum = tree[L(id)].sum+tree[R(id)].sum + tree[id].val;
}
void rotate(ll id,ll kind){ //kind=0表示左旋,kind=1表示右旋
	ll y = Father(id);
	push_down(id); push_down(y);
	tree[y].ch[kind^1] = tree[id].ch[kind];
	Father( tree[id].ch[kind] ) = y;
	if(Father(y))
		tree[Father(y)].ch[R(Father(y))==y] = id;
	Father(id) = Father(y);
	tree[id].ch[kind] = y;
	Father(y) = id;
	push_up(y);
}
void splay(ll id, ll goal){
	push_down(id);
	while(Father(id) != goal)
	{
		if(Father( Father(id) ) == goal)
			rotate(id,L( Father(id) ) == id);
		else
		{
			int y = Father(id); //y为父节点
			int kind = L( Father(y) ) == y;
			if(tree[y].ch[kind] == id)
			{
				rotate(id,kind^1);
				rotate(id,kind);
			}
			else
			{
				rotate(y,kind);
				rotate(id,kind);
			}
		}
	}
	push_up(id);
	if(goal == 0) root = id;
}
void rotateto(ll k, ll goal){ //把第k个节点转到goal下
	ll id = root;
	push_down(id);
	while(tree[L(id)].size != k)
	{
		if(tree[L(id)].size > k)
			id = L(id);
		else
		{
			k -= (tree[L(id)].size + 1);
			id = R(id);
		}
		push_down(id);
	}
	splay(id, goal);
}
ll query(ll l, ll r){
	rotateto(l-1, 0);
	rotateto(r+1, root);
	return tree[L( R(root) )].sum;
}
void update(ll l, ll r, ll v){
	rotateto(l-1, 0);
	rotateto(r+1,root);
	ll tmp = L( R(root) );
	tree[tmp].add += v;
	tree[tmp].sum += (ll)tree[tmp].size*v;
}
void build(ll l, ll r, ll& id, ll fa){
	if(l > r)return ;
	int mid = Mid(l,r);
	Newnode(id,fa,num[mid]);
	build(l,mid-1,L(id),id);
	build(mid+1,r,R(id),id);
	push_up(id);
}
ll n, q;
void init(){
	for(ll i = 0; i < n; i++)scanf("%lld",&num[i]);
	root = tot = 0;
	Father(0) = L(0) = R(0) = tree[0].size = 0;
	tree[0].sum = tree[0].val = 0;

	Newnode(root, 0, -1);
	Newnode(R(root), root, -1);
	tree[root].size = 2;
	build(0, n-1, L( R(root) ), R(root));
	push_up(R(root));
	push_up(root);
}
int main(){
	ll l, r, v;
	char str[5];
	scanf("%lld %lld",&n,&q);
	init();
	while(q--){
		scanf("%s",str);
		scanf("%lld%lld",&l,&r);
		if(str[0] == 'Q')
			printf("%lld\n",query(l,r));
		else
		{
			scanf("%lld",&v);
			update(l,r,v);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值