1. 程式人生 > >HDU - 5957 Query on a graph (bfs序 + 線段樹 + 分類大討論)

HDU - 5957 Query on a graph (bfs序 + 線段樹 + 分類大討論)

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5957

題目大意:給出一個n個點n條邊的圖,保證圖中沒有自環和重邊,圖中的結點的初始權值為0。接下來進行q次操作,每次操作有以下兩種:

MODIFY u k d:將與點u的距離小於等於k的點的權值加上d;

QUERY u k:查詢所有與點u的距離小於等於k的點的權值和。

題目思路:由於給出的圖是n個點和n條邊的,所以我們就可以把這個圖分成一棵樹加上一條額外的邊。

現在我們先考慮如果這個圖是一棵樹的情況要如何處理。

既然要求區間修改和區間查詢,我們肯定是考慮用線段樹來維護的,現在就考慮要如何用線段樹來維護。

由於k<=2,所以對於一個節點u在更新和查詢的時候,對這次操作會有影響的只有fa[u],fa[fa[u]]以及son[u],son[son[u]],由樹的性質我們可以知道,u的父親是唯一確定的,同理u的父親的父親也是唯一確定的,所以對於這兩種情況我們用線段樹的單點更新或者單點查詢即可。

那麼現在就是要來維護節點u的兒子節點的資訊,根據bfs的性質,如果按照bfs序進行標號,那麼節點u的兒子的編號就會是連續的,那麼我們就可以用lb[u]來表示節點u的兒子中最小的編號,rb[u]就表示節點u的兒子中最大的編號,這樣每次對[lb[u],rb[u]]進行區間更新和區間查詢就可以解決問題。

同理,我們可以用Lb[u]Rb[u]來維護節點u的孫子(即兒子節點的兒子節點)的最小編號和最大編號,同樣用線段樹可以進行維護和查詢。

現在考慮加入那一條額外的邊[U,V]的情況,加入這一條邊的處理方式其實和前面是一樣的,由於k<=2,所以會影響到的結點仍舊是父親以及兒子節點。但有一點就是要進行去重,可能你在前面沒有處理額外邊的時候就已經將一些結點的權值加進去了,這裡就需要進行分類大討論了,分為額外邊在當前節點上,額外邊在當前節點的父親節點上,額外邊在當前節點的兒子節點上,然後再根據實際情況考慮去除重複的部分。(雖然是已經過了這題,但這個分類討論是真的噁心QAQ)

具體實現看程式碼:

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define fuck(x) cout<<"["<<#x<<" " << (x) << "]"<<endl
using namespace std;
typedef long long ll;
typedef pair<int, int>pii;
const int MX = 1e5 + 4;

int n, q, _;
vector<int>E[MX];
ll sum[MX << 2], tag[MX << 2];
void push_up(int rt) {
	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void push_down(int l, int r, int rt) {
	if (tag[rt]) {
		int m = (l + r) >> 1;
		tag[rt << 1] += tag[rt];
		tag[rt << 1 | 1] += tag[rt];
		sum[rt << 1] += (ll)(m - l + 1) * tag[rt];
		sum[rt << 1 | 1] += (ll)(r - m) * tag[rt];
		tag[rt] = 0;
	}
}
void build(int l, int r, int rt) {
	sum[rt] = tag[rt] = 0;
	if (l == r) return;
	int m = (l + r) >> 1;
	build(lson);
	build(rson);
	push_up(rt);
}
void update(int L, int R, int d, int l, int r, int rt) {
	if (L <= l && r <= R) {
		tag[rt] += d;
		sum[rt] += (ll)(r - l + 1) * d;
		return;
	}
	push_down(l, r, rt);
	int m = (l + r) >> 1;
	if (L <= m) update(L, R, d, lson);
	if (R > m) update(L, R, d, rson);
	push_up(rt);
}
ll query(int L, int R, int l, int r, int rt) {
	if (L <= l && r <= R) return sum[rt];
	push_down(l, r, rt);
	int m = (l + r) >> 1;
	ll res = 0;
	if (L <= m) res += query(L, R, lson);
	if (R > m) res += query(L, R, rson);
	return res;
}

int U, V;
int P[MX];
int Find(int x) {
	return P[x] == x ? x : (P[x] = Find(P[x]));
}
void Union(int u, int v) {
	int uu = Find(u), vv = Find(v);
	if (uu == vv) {
		U = u;
		V = v;
		return;
	}
	E[u].pb(v); E[v].pb(u);
	P[uu] = vv;
}

int id[MX], fa[MX], dfn;
int lb[MX], rb[MX];
int Lb[MX], Rb[MX];
void bfs(int s) {
	queue<int>que;
	que.push(s); dfn = 0;
	while (!que.empty()) {
		int u = que.front(); que.pop();
		id[u] = ++dfn;
		lb[fa[u]] = min(lb[fa[u]], id[u]);
		rb[fa[u]] = max(rb[fa[u]], id[u]);
		Lb[fa[fa[u]]] = min(Lb[fa[fa[u]]], id[u]);
		Rb[fa[fa[u]]] = max(Rb[fa[fa[u]]], id[u]);
		for (auto v : E[u]) {
			if (v == fa[u]) continue;
			fa[v] = u;
			que.push(v);
		}
	}
}
ll cal(int u, int k) {
	ll res = 0;
	if (k == 0) res = query(id[u], id[u], 1, n, 1);
	else if (k == 1) {
		res = query(id[u], id[u], 1, n, 1);
		if (rb[u]) res += query(lb[u], rb[u], 1, n, 1);
		if (fa[u]) res += query(id[fa[u]], id[fa[u]], 1, n, 1);
		if (u == U) res += query(id[V], id[V], 1, n, 1);
		if (u == V) res += query(id[U], id[U], 1, n, 1);
	} else {
		res = query(id[u], id[u], 1, n, 1);
		if (rb[u]) res += query(lb[u], rb[u], 1, n, 1);
		if (fa[u]) res += query(id[fa[u]], id[fa[u]], 1, n, 1);
		if (fa[fa[u]]) res += query(id[fa[fa[u]]], id[fa[fa[u]]], 1, n, 1);
		if (Rb[u]) res += query(Lb[u], Rb[u], 1, n, 1);
		if (rb[fa[u]]) res += query(lb[fa[u]], rb[fa[u]], 1, n, 1) - query(id[u], id[u], 1, n, 1);

		if (u == U) {
			if (V != fa[fa[u]] && (id[V] < Lb[u] || id[V] > Rb[u]) && (id[V] < lb[fa[u]] || id[V] > rb[fa[u]]))
				res += query(id[V], id[V], 1, n, 1);
			if (V == fa[fa[u]]) {
				if (fa[V]) res += query(id[fa[V]], id[fa[V]], 1, n, 1);
				if (rb[V]) res += query(lb[V], rb[V], 1, n, 1) - query(id[fa[u]], id[fa[u]], 1, n, 1);
			} else if (id[V] >= Lb[u] && id[V] <= Rb[u]) {
				if (rb[V]) res += query(lb[V], rb[V], 1, n, 1);
			} else if (id[V] >= lb[fa[u]] && id[V] <= rb[fa[u]]) {
				if (rb[V]) res += query(lb[V], rb[V], 1, n, 1);
			} else {
				if (fa[V] && fa[V] != fa[fa[u]] && (id[fa[V]] < lb[fa[u]] || id[fa[V]] > rb[fa[u]]) && (id[fa[V]] < Lb[u] || id[fa[V]] > Rb[u]))
					res += query(id[fa[V]], id[fa[V]], 1, n, 1);
				if (rb[V]) {
					res += query(lb[V], rb[V], 1, n, 1);
					if (id[fa[fa[u]]] <= rb[V] && id[fa[fa[u]]] >= lb[V])
						res -= query(id[fa[fa[u]]], id[fa[fa[u]]], 1, n, 1);
				}
			}
		}
		if (u == V) {
			if (U != fa[fa[u]] && (id[U] < Lb[u] || id[U] > Rb[u]) && (id[U] < lb[fa[u]] || id[U] > rb[fa[u]]))
				res += query(id[U], id[U], 1, n, 1);
			if (U == fa[fa[u]]) {
				if (fa[U]) res += query(id[fa[U]], id[fa[U]], 1, n, 1);
				if (rb[U]) res += query(lb[U], rb[U], 1, n, 1) - query(id[fa[u]], id[fa[u]], 1, n, 1);
			} else if (id[U] >= Lb[u] && id[U] <= Rb[u]) {
				if (rb[U]) res += query(lb[U], rb[U], 1, n, 1);
			} else if (id[U] >= lb[fa[u]] && id[U] <= rb[fa[u]]) {
				if (rb[U]) res += query(lb[U], rb[U], 1, n, 1);
			} else {
				if (fa[U] && fa[U] != fa[fa[u]] && (id[fa[U]] < lb[fa[u]] || id[fa[U]] > rb[fa[u]]) && (id[fa[U]] < Lb[u] || id[fa[U]] > Rb[u]))
					res += query(id[fa[U]], id[fa[U]], 1, n, 1);
				if (rb[U]) {
					res += query(lb[U], rb[U], 1, n, 1);
					if (id[fa[fa[u]]] <= rb[U] && id[fa[fa[u]]] >= lb[U])
						res -= query(id[fa[fa[u]]], id[fa[fa[u]]], 1, n, 1);
				}
			}
		}

		if (fa[u] == U) {
			if ((id[V] < Lb[u] || id[V] > Rb[u]) && (id[V] < lb[u] || id[V] > rb[u]))
				res += query(id[V], id[V], 1, n, 1);
		}
		if (fa[u] == V) {
			if ((id[U] < Lb[u] || id[U] > Rb[u]) && (id[U] < lb[u] || id[U] > rb[u]))
				res += query(id[U], id[U], 1, n, 1);
		}

		if (id[U] <= rb[u] && id[U] >= lb[u]) {
			if (V != fa[u] && V != fa[fa[u]] && (id[V] < lb[fa[u]] || id[V] > rb[fa[u]]) && (id[V] < lb[u] || id[V] > rb[u]) && (id[V] < Lb[u] || id[V] > Rb[u]))
				res += query(id[V], id[V], 1, n, 1);
		}

		if (id[V] <= rb[u] && id[V] >= lb[u]) {
			if (U != fa[u] && U != fa[fa[u]] && (id[U] < lb[fa[u]] || id[U] > rb[fa[u]]) && (id[U] < lb[u] || id[U] > rb[u]) && (id[U] < Lb[u] || id[U] > Rb[u]))
				res += query(id[U], id[U], 1, n, 1);
		}
	}
	return res;
}

void upd(int u, int k, int d) {
	if (k == 0) update(id[u], id[u], d, 1, n, 1);
	else if (k == 1) {
		update(id[u], id[u], d, 1, n, 1);
		if (rb[u]) update(lb[u], rb[u], d, 1, n, 1);
		if (fa[u]) update(id[fa[u]], id[fa[u]], d, 1, n, 1);
		if (u == U) update(id[V], id[V], d, 1, n, 1);
		if (u == V) update(id[U], id[U], d, 1, n, 1);
	} else {
		update(id[u], id[u], d, 1, n, 1);
		if (rb[u]) update(lb[u], rb[u], d, 1, n, 1);
		if (fa[u]) update(id[fa[u]], id[fa[u]], d, 1, n, 1);
		if (fa[fa[u]]) update(id[fa[fa[u]]], id[fa[fa[u]]], d, 1, n, 1);
		if (Rb[u]) update(Lb[u], Rb[u], d, 1, n, 1);
		if (rb[fa[u]]) update(lb[fa[u]], rb[fa[u]], d, 1, n, 1), update(id[u], id[u], -d, 1, n, 1);
		if (u == U) {
			if (V != fa[fa[u]] && (id[V] < Lb[u] || id[V] > Rb[u]) && (id[V] < lb[fa[u]] || id[V] > rb[fa[u]]))
				update(id[V], id[V], d, 1, n, 1);
			if (V == fa[fa[u]]) {
				if (fa[V]) update(id[fa[V]], id[fa[V]], d, 1, n, 1);
				if (rb[V]) update(lb[V], rb[V], d, 1, n, 1), update(id[fa[u]], id[fa[u]], -d, 1, n, 1);
			} else if (id[V] >= Lb[u] && id[V] <= Rb[u]) {
				if (rb[V]) update(lb[V], rb[V], d, 1, n, 1);
			} else if (id[V] >= lb[fa[u]] && id[V] <= rb[fa[u]]) {
				if (rb[V]) update(lb[V], rb[V], d, 1, n, 1);
			} else {
				if (fa[V] && fa[V] != fa[fa[u]] && (id[fa[V]] < lb[fa[u]] || id[fa[V]] > rb[fa[u]]) && (id[fa[V]] < Lb[u] || id[fa[V]] > Rb[u]))
					update(id[fa[V]], id[fa[V]], d, 1, n, 1);
				if (rb[V]) {
					update(lb[V], rb[V], d, 1, n, 1);
					if (id[fa[fa[u]]] <= rb[V] && id[fa[fa[u]]] >= lb[V]) update(id[fa[fa[u]]], id[fa[fa[u]]], -d, 1, n, 1);
				}
			}
		}
		if (u == V) {
			if (U != fa[fa[u]] && (id[U] < Lb[u] || id[U] > Rb[u]) && (id[U] < lb[fa[u]] || id[U] > rb[fa[u]]))
				update(id[U], id[U], d, 1, n, 1);
			if (U == fa[fa[u]]) {
				if (fa[U]) update(id[fa[U]], id[fa[U]], d, 1, n, 1);
				if (rb[U]) update(lb[U], rb[U], d, 1, n, 1), update(id[fa[u]], id[fa[u]], -d, 1, n, 1);
			} else if (id[U] >= Lb[u] && id[U] <= Rb[u]) {
				if (rb[U]) update(lb[U], rb[U], d, 1, n, 1);
			} else if (id[U] >= lb[fa[u]] && id[U] <= rb[fa[u]]) {
				if (rb[U]) update(lb[V], rb[U], d, 1, n, 1);
			} else {
				if (fa[U] && fa[U] != fa[fa[u]] && (id[fa[U]] < lb[fa[u]] || id[fa[U]] > rb[fa[u]]) && (id[fa[U]] < Lb[u] || id[fa[U]] > Rb[u])) {
					update(id[fa[U]], id[fa[U]], d, 1, n, 1);
				}
				if (rb[U]) {
					update(lb[U], rb[U], d, 1, n, 1);
					if (id[fa[fa[u]]] <= rb[U] && id[fa[fa[u]]] >= lb[U]) update(id[fa[fa[u]]], id[fa[fa[u]]], -d, 1, n, 1);
				}
			}
		}

		if (fa[u] == U) {
			if ((id[V] < Lb[u] || id[V] > Rb[u]) && (id[V] < lb[u] || id[V] > rb[u]))
				update(id[V], id[V], d, 1, n, 1);
		}
		if (fa[u] == V) {
			if ((id[U] < Lb[u] || id[U] > Rb[u]) && (id[U] < lb[u] || id[U] > rb[u]))
				update(id[U], id[U], d, 1, n, 1);
		}

		if (id[U] <= rb[u] && id[U] >= lb[u]) {
			if (V != fa[u] && V != fa[fa[u]] && (id[V] < lb[fa[u]] || id[V] > rb[fa[u]]) && (id[V] < lb[u] || id[V] > rb[u]) && (id[V] < Lb[u] || id[V] > Rb[u]))
				update(id[V], id[V], d, 1, n, 1);
		}

		if (id[V] <= rb[u] && id[V] >= lb[u]) {
			if (U != fa[u] && U != fa[fa[u]] && (id[U] < lb[fa[u]] || id[U] > rb[fa[u]]) && (id[U] < lb[u] || id[U] > rb[u]) && (id[U] < Lb[u] || id[U] > Rb[u]))
				update(id[U], id[U], d, 1, n, 1);
		}
	}
}

int main() {
	// freopen("in.txt", "r", stdin);
	for (scanf("%d", &_); _; _--) {
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
			E[i].clear(), P[i] = i, Lb[i] = lb[i] = n + 1, Rb[i] = rb[i] = 0;
		for (int i = 1; i <= n; i++) {
			int u, v;
			scanf("%d%d", &u, &v);
			Union(u, v);
		}
		bfs(1);
		build(1, n, 1);
		char op[15];
		int u, k, d;
		scanf("%d", &q);
		while (q--) {
			scanf("%s", op);
			if (op[0] == 'Q') {
				scanf("%d%d", &u, &k);
				printf("%lld\n", cal(u, k));
			} else {
				scanf("%d%d%d", &u, &k, &d);
				upd(u, k, d);
			}
		}
	}
	return 0;
}