HDU - 5957 Query on a graph (bfs序 + 线段树 + 分类大讨论)

40 篇文章 0 订阅
7 篇文章 0 订阅

题目链接: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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值