HDU 4348 To the moon(可持久化線段樹+內存池)


To the moon

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 7073    Accepted Submission(s): 1651


Problem Description
Background
To The Moon is a independent game released in November 2011, it is a role-playing adventure game powered by RPG Maker.
The premise of To The Moon is based around a technology that allows us to permanently reconstruct the memory on dying man. In this problem, we'll give you a chance, to implement the logic behind the scene.

You‘ve been given N integers A[1], A[2],..., A[N]. On these integers, you need to implement the following operations:
1. C l r d: Adding a constant d for every {Ai | l <= i <= r}, and increase the time stamp by 1, this is the only operation that will cause the time stamp increase. 
2. Q l r: Querying the current sum of {Ai | l <= i <= r}.
3. H l r t: Querying a history sum of {Ai | l <= i <= r} in time t.
4. B t: Back to time t. And once you decide return to a past, you can never be access to a forward edition anymore.
.. N, M ≤ 105, |A[i]| ≤ 109, 1 ≤ l ≤ r ≤ N, |d| ≤ 104 .. the system start from time 0, and the first modification is in time 1, t ≥ 0, and won't introduce you to a future state.
 

Input
n m
A1 A2 ... An
... (here following the m operations. )
 

Output
... (for each query, simply print the result. )
 

Sample Input
10 51 2 3 4 5 6 7 8 9 10Q 4 4Q 1 10Q 2 4C 3 6 3Q 2 42 40 0C 1 1 1C 2 2 -1Q 1 2H 1 2 1
 
Sample Output
45591501
 

Author
HIT
 

Source


【思路】

題目要求在區間修改、區間查詢的基礎上,能夠查詢歷史版本,並可以回退到之前版本。

這就要求我們用可持久化的數據結構,以在規定時間內獲得歷史版本並且維護它。區間修改和查詢用線段樹加上懶惰標記即可做,然而在此卻不好進行常規的push_down操作,原因有二:1、push_down若向更早版本的低位壓,則會導致數據污染,此時查詢更早版本就會出錯。2、push_down若向當前版本的低位壓,就會使得新增加的節點呈現錯序排布,此後進行B t操作就不好回收節點了,而且push_down也會生出大量節點,浪費內存。因此,我選用了更省空間寫法,利用懶惰標記,當統計[l, r]區間時,在查詢它的路上每一層若有mark,都是要給它加上的,最後加上[l, r]自己的sum即可。此外注意,既然不push_down了,也就不能push_up,因爲若先改一個大點的區間,再改一個包含在它裏面的小區間時,會導致錯誤的回溯,爲保證sum的統一性,我們在遞歸修改時順手給高層次的區間加上即可。

此題尤其卡內存,線段樹的左右界甚至不能寫入節點,而應該用參數傳遞。


【代碼】

//************************************************************************
// File Name: main.cpp
// Author: Shili_Xu
// E-Mail: [email protected] 
// Created Time: 2018年02月13日 星期二 13時22分53秒
//************************************************************************

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 1e5 + 5;

struct segment {
	long long sum, mark;
	int lson, rson;
};

int n, m, cnt, time;
int a[MAXN], root[MAXN];
segment seg[MAXN * 30];

void build(int left, int right, int &rt)
{
	rt = ++cnt;
	seg[rt].mark = 0;
	int mid = (left + right) >> 1;
	if (left == right) {
		seg[rt].sum = (long long)a[mid];
		return;
	}
	build(left, mid, seg[rt].lson);
	build(mid + 1, right, seg[rt].rson);
	seg[rt].sum = seg[seg[rt].lson].sum + seg[seg[rt].rson].sum;
}

void modify(int l, int r, long long num, int left, int right, int pre, int &now)
{
	now = ++cnt;
	seg[now] = seg[pre];
	if (l <= left && right <= r) {
		seg[now].sum += num * (right - left + 1);
		seg[now].mark += num;
		return;
	}
	int mid = (left + right) >> 1;
	if (l <= mid) {
		seg[now].sum += num * (min(r, mid) - max(l, left) + 1);
		modify(l, r, num, left, mid, seg[pre].lson, seg[now].lson);
	}
	if (r >= mid + 1) {
		seg[now].sum += num * (min(r, right) - max(l, mid + 1) + 1);
		modify(l, r, num, mid + 1, right, seg[pre].rson, seg[now].rson);
	}
}

long long query(int l, int r, int left, int right, int rt)
{
	if (l <= left && right <= r) return seg[rt].sum;
	int mid = (left + right) >> 1;
	long long ans = 0;
	if (left <= l && r <= right) ans += seg[rt].mark * (r - l + 1);
	else
	if (l <= left && r <= right) ans += seg[rt].mark * (r - left + 1);
	else
	if (left <= l && right <= r) ans += seg[rt].mark * (right - l + 1);
	if (l <= mid) ans += query(l, r, left, mid, seg[rt].lson);
	if (r >= mid + 1) ans += query(l, r, mid + 1, right, seg[rt].rson);
	return ans;
}

int main()
{
	bool flag = false;
	while (scanf("%d %d", &n, &m) == 2) {
		if (flag)
			printf("\n");
		else
			flag = true;
		for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
		cnt = 0; time = 0;
		build(1, n, root[0]);
		while (m--) {
			char mes[2];
			scanf("%s", mes);
			if (mes[0] == 'C') {
				int l, r;
				long long d;
				scanf("%d %d %lld", &l, &r, &d);
				time++;
				modify(l, r, d, 1, n, root[time - 1], root[time]);
			}
			if (mes[0] == 'Q') {
				int l, r;
				scanf("%d %d", &l, &r);
				printf("%lld\n", query(l, r, 1, n, root[time]));
			}
			if (mes[0] == 'H') {
				int l, r, t;
				scanf("%d %d %d", &l, &r, &t);
				printf("%lld\n", query(l, r, 1, n, root[t]));
			}
			if (mes[0] == 'B') {
				int t;
				scanf("%d", &t);
				if (t < time) {
					cnt = root[t + 1] - 1;
					time = t;
				}
			}
		}
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章