Sobre

Mantem uma floresta enraizada dinamicamente

e permite queries/updates em sub-arvore

Chamar ETT E(n, v), passando n = numero de vertices

e v = vector com os valores de cada vertice (se for vazio,

constroi tudo com 0

link(v, u) cria uma aresta de v pra u, de forma que u se torna

o pai de v (eh preciso que v seja raiz anteriormente)

cut(v) corta a resta de v para o pai

query(v) retorna a soma dos valores da sub-arvore de v

update(v, val) soma val em todos os vertices da sub-arvore de v

update_v(v, val) muda o valor do vertice v para val

is_in_subtree(v, u) responde se o vertice u esta na sub-arvore de v

Tudo O(log(n)) com alta probabilidade

Link original: eulerTourTree.cpp

Código

  mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count());

template<typename T> struct ETT {
	// treap
	struct node {
		node *l, *r, *p;
		int pr, sz;
		T val, sub, lazy;
		int id;
		bool f; // se eh o 'first'
		int qt_f; // numero de firsts na subarvore
		node(int id_, T v, bool f_ = 0) : l(NULL), r(NULL), p(NULL), pr(rng()),
			sz(1), val(v), sub(v), lazy(), id(id_), f(f_), qt_f(f_) {}
		void prop() {
			if (lazy != T()) {
				if (f) val += lazy;
				sub += lazy*sz;
				if (l) l->lazy += lazy;
				if (r) r->lazy += lazy;
			}
			lazy = T();
		}
		void update() {
			sz = 1, sub = val, qt_f = f;
			if (l) l->prop(), sz += l->sz, sub += l->sub, qt_f += l->qt_f;
			if (r) r->prop(), sz += r->sz, sub += r->sub, qt_f += r->qt_f;
		}
	};

	node* root;

	int size(node* x) { return x ? x->sz : 0; }
	void join(node* l, node* r, node*& i) { // assume que l < r
		if (!l or !r) return void(i = l ? l : r);
		l->prop(), r->prop();
		if (l->pr > r->pr) join(l->r, r, l->r), l->r->p = i = l;
		else join(l, r->l, r->l), r->l->p = i = r;
		i->update();
	}
	void split(node* i, node*& l, node*& r, int v, int key = 0) {
		if (!i) return void(r = l = NULL);
		i->prop();
		if (key + size(i->l) < v) {
			split(i->r, i->r, r, v, key+size(i->l)+1), l = i;
			if (r) r->p = NULL;
			if (i->r) i->r->p = i;
		} else {
			split(i->l, l, i->l, v, key), r = i;
			if (l) l->p = NULL;
			if (i->l) i->l->p = i;
		}
		i->update();
	}
	int get_idx(node* i) {
		int ret = size(i->l);
		for (; i->p; i = i->p) {
			node* pai = i->p;
			if (i != pai->l) ret += size(pai->l) + 1;
		}
		return ret;
	}
	node* get_min(node* i) {
		if (!i) return NULL;
		return i->l ? get_min(i->l) : i;
	}
	node* get_max(node* i) {
		if (!i) return NULL;
		return i->r ? get_max(i->r) : i;
	}
	// fim da treap

	vector<node*> first, last;

	ETT(int n, vector<T> v = {}) : root(NULL), first(n), last(n) {
		if (!v.size()) v = vector<T>(n);
		for (int i = 0; i < n; i++) {
			first[i] = last[i] = new node(i, v[i], 1);
			join(root, first[i], root);
		}
	}
	ETT(const ETT& t) { throw logic_error("Nao copiar a ETT!"); }
	~ETT() {
		vector<node*> q = {root};
		while (q.size()) {
			node* x = q.back(); q.pop_back();
			if (!x) continue;
			q.push_back(x->l), q.push_back(x->r);
			delete x;
		}
	}

	pair<int, int> get_range(int i) {
		return {get_idx(first[i]), get_idx(last[i])};
	}
	void link(int v, int u) { // 'v' tem que ser raiz
		auto [lv, rv] = get_range(v);
		int ru = get_idx(last[u]);
		
		node* V;
		node *L, *M, *R;
		split(root, M, R, rv+1), split(M, L, M, lv);
		V = M;
		join(L, R, root);

		split(root, L, R, ru+1);
		join(L, V, L);
		join(L, last[u] = new node(u, T() /* elemento neutro */), L);
		join(L, R, root);
	}
	void cut(int v) {
		auto [l, r] = get_range(v);

		node *L, *M, *R;
		split(root, M, R, r+1), split(M, L, M, l);
		node *LL = get_max(L), *RR = get_min(R);
		if (LL and RR and LL->id == RR->id) { // remove duplicata
			 if (last[RR->id] == RR) last[RR->id] = LL;
			 node *A, *B;
			 split(R, A, B, 1);
			 delete A;
			 R = B;
		}
		join(L, R, root);
		join(root, M, root);
	}
	T query(int v) {
		auto [l, r] = get_range(v);
		node *L, *M, *R;
		split(root, M, R, r+1), split(M, L, M, l);
		T ans = M->sub;
		join(L, M, M), join(M, R, root);
		return ans;
	}
	void update(int v, T val) { // soma val em todo mundo da subarvore
		auto [l, r] = get_range(v);
		node *L, *M, *R;
		split(root, M, R, r+1), split(M, L, M, l);
		M->lazy += val;
		join(L, M, M), join(M, R, root);
	}
	void update_v(int v, T val) { // muda o valor de v pra val
		int l = get_idx(first[v]);
		node *L, *M, *R;
		split(root, M, R, l+1), split(M, L, M, l);
		M->val = M->sub = val;
		join(L, M, M), join(M, R, root);
	}
	bool is_in_subtree(int v, int u) { // se u ta na subtree de v
		auto [lv, rv] = get_range(v);
		auto [lu, ru] = get_range(u);
		return lv <= lu and ru <= rv;
	}

	void print(node* i) {
		if (!i) return;
		print(i->l);
		cout << i->id+1 << " ";
		print(i->r);
	}
	void print() { print(root); cout << endl; }
};