#pragma pack(1)
#include <iostream>
using namespace std;

const int maxn = 1e5;
struct Node { //узел дерева
	Node *lp, *rp; //дочерние узлы / поддеревья
	int val; //сумма (или другой параметр) для поддерева
};

Node nodes[maxn * 30]; //хранилище узлов, все узлы изначально нулевые (0,null_ptr,null_ptr)
Node* roots[maxn + 1]; 
Node* lastnode = nodes + 1; //первый из свободных узлов

int getsum(Node* v, int l, int r, int x, int y) { //найти сумму элементов от x-го до y-го
	if (v == nullptr) return 0;                   //в поддереве начиная с узла (v,l,r)
	if(l == x && r == y) {
		return v -> val;
	}
	else {
		int m = (l + r) / 2;
		if(y <= m) {
			return getsum(v -> lp, l, m, x, y);
		}
		else if(x > m) {
			return getsum(v -> rp, m + 1, r, x, y);
		}
		else {
			return getsum(v -> lp, l, m, x, m) + getsum(v -> rp, m + 1, r, m + 1, y);
		}
	}
}

void update(Node*& v, int l, int r, int pos, int val) { 
	//обновление элемента с позицией pos в поддереве (v,l,r) (присваивание значения val)
	//при обновлении всегда создается новый узел
	Node* old = v; //старый узел (не трогаем!)
	v = lastnode++; //новый узел из хранилища
	if(old != nullptr) { // если старый узел существовал
		*v = *old; //копируем старый узел
	} //иначе новый узел пуст (0,null_ptr,null_ptr)
	if(l == r) { //и l==r==pos
		v -> val = val;
	}
	else {
		int m = (r + l) / 2;
		if(pos <= m) {
			update(v -> lp, l, m, pos, val);//обновление левого поддерева
		}
		else {
			update(v -> rp, m + 1, r, pos, val);//обновление правого поддерева
		}
		v -> val = 0; //начало пересчета суммы
		if(v -> lp != nullptr) //если левое поддерево существует
			v -> val += v -> lp -> val; //учесть его сумму
		if(v -> rp != nullptr)
			v -> val += v -> rp -> val;
	}
}

void print(Node* root) {
	cout << root -> val << " ";
	if(root -> lp != nullptr) {
		print(root -> lp);
	}
	if(root -> rp != nullptr) {
		print(root -> rp);
	}
}

int main() {
	const int N = 1e9;
	int a[maxn]; //массив
	int n;
	cin >> n;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
	} //ввели с клавиатуры
	//roots[0] == null_ptr (пустое дерево)
	for(int i = 1; i <= n; i++) {
		roots[i] = roots[i - 1]; //новый корень указывает туда же, что и старый
		update(roots[i], 1, N, i, a[i]); //обновляем дерево с новым корнем,
		//при этом создается действительно новый корень и некоторые новые узлы
		//корень имеет диапазон [1,N] и i-тому элементу присваивается значение a[i]
	}
	// cout << roots[2] -> val << endl;
	for(int i = 1; i <= n; i++) {
		cout << roots[i] -> val << " ";
	}
	cout << endl;
	// print(roots[n]);
	cout <<getsum(roots[2],1,N,2,3) <<endl; //какая была сумма от 2 до 3 в момент времени 2
	roots[n+1] = roots[n]; //следующий момент времени n+1
	update(roots[n+1], 1, N, 2, 0); //обнуляем второй элемент
	cout <<getsum(roots[n],1,N,1,3) <<endl;
	cout <<getsum(roots[n+1],1,N,1,3) <<endl;
	return 0;
}