SPOJ TO THE MOON 主席树(有动态修改)

题目大意:

       题目大意:给定一些数字,有以下几个操作

       a、[L,R]区间的数字变化D的数值。并且时间向前推进

       b、询问某个时间的[L,R]区间的数字之和,这不花费时间

       c、回到X时间。


主席树带动态操作裸题。  但是也可以用主席树,不push版本


AC CODE: 300+M内存使用


#include <bits/stdc++.h>
using namespace std;

#define pr(x)	x
#define prln(x)	x

//#define pr(x)	cout<< #x << " = " <<x<<" "
//#define prln(x)	cout<< #x << " = " <<x<<endl

const int maxn = 123456;
const int maxnode = maxn * 100;
int n, m;

struct node  
{  
    int lson, rson;  
    long long val;//区间权重  
    long long change;//区间修改值,为0表示没有需要传递的  
    int ver;
}tree[maxnode];  
int tail, root[maxn]; 

long long w[maxn];
char inp[15];

int ql, qr, qans, qver;  
#define LSON tree[o].lson,L, M  
#define RSON tree[o].rson, M + 1 , R  
#define SELF o,L,R  
#define lc tree[o].lson  
#define rc tree[o].rson  

void push_down(int o, int L, int R)//向下传递标记, o节点的val值不变
{  
	if (tree[o].change && L < R)  
	{  
		if (tree[lc].ver != qver)
		{
			tree[++tail] = tree[lc];
			tree[o].lson = tail;
			tree[lc].ver = qver;
		}
		if (tree[rc].ver != qver)
		{
			tree[++tail] = tree[rc];
			tree[o].rson = tail;
			tree[rc].ver = qver;
		}
		tree[lc].change += tree[o].change;  
		tree[rc].change += tree[o].change;  
		tree[o].change = 0;  
	}  
}  


//更新o节点的val信息。那么就需要把儿子的信息汇总到o
//要特别注意,儿子的懒人标记的信息和val信息汇总
void maintain(int o, int L, int R) 
{  
	if (L < R)  
	{  
		int M = L+(R-L)/2;  
		tree[o].val = tree[lc].val + tree[rc].val + tree[lc].change * (M-L+1) + tree[rc].change * (R-M);  
	}  
	//L==R的情况,不包含的左右儿子,所以再query里询问到的节点,直接结合处理了
}  


void build(int o, int L, int R)  
{  
	tree[o].change = 0;  
	tree[o].ver = 0;//一开始建树,建的是0号版本的
	if (L== R)  
	{  
		tree[o].val = w[L];  
		return ;  
	}  
	tree[o].lson = ++ tail;  
	tree[o].rson = ++ tail;  
	int M = L + (R - L) / 2;  
	build(LSON);  
	build(RSON);  
	maintain(SELF);
}


void insert(int &o, int L, int R)
{
	tree[++ tail] = tree[o];
	o = tail;
	tree[o].ver = qver;
	if (ql <= L && R <= qr)
	{
		tree[o].change += qans;
		return;
	}
	push_down(SELF);
	int M = L + (R-L)/2;
	if (ql <= M)	insert(LSON);
	else maintain(LSON);
	if (qr > M)	insert(RSON);
	else maintain(RSON);
	maintain(SELF);
}

long long query(int o, int L, int R)  
{  
	if (tree[o].ver != qver)
	{
		tree[++tail] = tree[o];
		o = tail;
		tree[o].ver = qver;
	}
	if (ql <= L && R <= qr)  
	{  
		//返回的值需要考虑到懒人标记信息
		return tree[o].val + tree[o].change * (R-L+1);//因为根节点的传递标记一直都在  
	}  	
	push_down(SELF);  
	int M = L + (R - L) / 2;  
	long long ret = 0;  
	if (ql <= M) ret += query(LSON);  
	else maintain(LSON);  
	if (qr > M)  ret += query(RSON);  
	else maintain(RSON);  
	maintain(SELF);  
	return ret;  
}  

void init()
{
	for (int i = 1; i <=n; ++ i)	scanf("%lld", &w[i]);//读入一些数据
	root[0] = 0;
	tail = 0;
	build(root[0], 1, n);
}

void doit()
{
	int now =0;
	while (m--)
	{
		scanf("%s", inp);
		if (inp[0] == 'C')	//区间更新,now+1
		{
			++now;
			root[now] = root[now - 1];
			qver = now;
			scanf("%d%d%d", &ql, &qr, &qans);//ql,qr区间变化qans
			insert(root[now], 1, n);
		}
		if (inp[0]=='Q')	//询问当前
		{
			scanf("%d%d", &ql, &qr);
			qver = now;
			printf("%lld\n",query(root[now], 1, n));
		}
		if (inp[0]=='H')	//询问que时间的L,R区间和
		{
			scanf("%d%d%d", &ql, &qr, &qver);
			printf("%lld\n",query(root[qver], 1, n));
		}
		if (inp[0] == 'B')	//回到过去
		{
			scanf("%d", &now);
		}
	}
	puts("");
}

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值