牛客练习赛115 D:Genealogy in the trees题解

 这是一道模板题,区间可以用线段树来维护,也可以用树状数组来维护。

#include<bits/stdc++.h>
using namespace std;
//快读
int read() {
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c>'9') {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		x = x * 10 + c - '0', c = getchar();
	}
	return x * f;
}
const int N = 3e5 + 10;
vector<int> g[N];//存图
vector<int> p[N];//p,q
vector<pair<int, int>> q[N];//a,b,i
int ans[N];//答案

//树链剖分 重链剖分 【模板】
int fa[N], dep[N], son[N], siz[N];
void dfs1(int u, int father) {//求dep,son,siz,fa
	dep[u] = dep[father] + 1, fa[u] = father,siz[u]=1;
	for (auto t : g[u]) {
		if (t == father) continue;
		dfs1(t, u);
		siz[u] += siz[t];
		if (siz[son[u]] < siz[t]) {
			son[u] = t;
		}
	}
}
int top[N], indx[N],cnt;
void dfs2(int u, int t) {//求top,indx
	top[u] = t,indx[u]=++cnt;
	if (!son[u]) return;
	dfs2(son[u], t);
	for (auto v : g[u]) {
		if (v == son[u] || v == fa[u]) continue;
		dfs2(v, v);
	}
}
//

//线段树【模板】
#define lc u<<1
#define lr u<<1|1
struct node {
	int x, y;//区间
	int sum, lazy;
}tree[4*N];
void pushup(int u) {
	tree[u].sum = tree[lc].sum + tree[lr].sum;
}
void pushdown(int u) {//懒标记
	if (tree[u].lazy) {
		tree[lc].sum += tree[u].lazy * (tree[lc].y - tree[lc].x + 1);
		tree[lr].sum += tree[u].lazy * (tree[lr].y - tree[lr].x + 1);
		tree[lr].lazy += tree[u].lazy;
		tree[lc].lazy += tree[u].lazy;
		tree[u].lazy = 0;
	}
}
void build(int u, int l, int r) {
	tree[u] = { l,r,0,0 };
	if (l == r) return ;
	int mid = l + r >> 1;
	build(lc, l, mid);
	build(lr, mid + 1, r);
	pushup(u);
}
//查询
int query(int u,int l,int r) {
	if (tree[u].x >= l && tree[u].y <= r) return tree[u].sum;
	pushdown(u);
	int mid = tree[u].x + tree[u].y >> 1;
	int res = 0;
	if(l<=mid) res=query(lc, l, r);
	if (r > mid) res += query(lr, l, r);
	return res;
}
//【模板】 求树上最小权重和 
// 此题没有用到
int query_path(int u, int v) {
	int res = 0;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(v, u);
		res += query(1,indx[top[u]],indx[u]);
		u = fa[top[u]];
	}
	if (dep[u] < dep[v]) swap(v, u);
	res += query(1, indx[v], indx[u]);
	return res;
}
//修改
void updata(int u, int l, int r, int k) {
	if (tree[u].x >= l && tree[u].y <= r) {
		tree[u].sum += k * (tree[u].y - tree[u].x + 1);
		tree[u].lazy += k;//懒标记
		return;
	}
	pushdown(u);
	int mid = tree[u].x + tree[u].y >> 1;
	if (l <= mid) updata(lc, l, r, k);
	if (r > mid) updata(lr, l, r, k);
	pushup(u);
} 

void dfs3(int u, int father) {//求ans
	for (auto v : p[u]) {
		updata(1, indx[v], indx[v], 1);//记录q点的位置+1
	}
	for (auto t : q[u]) {//遍历在p子孙里的a的b
		int v = t.first, id = t.second;
		ans[id] = query(1, indx[v], indx[v] + siz[v] - 1);//如果q在b的子树里就加上
	}
	for (auto v : g[u]) {//继续遍历下一个节点
		if (v == father) continue;
		dfs3(v, u);
	}
	for (auto v : p[u]) {//子树遍历完后及时删除,因为要保证p是a的祖先
		updata(1, indx[v], indx[v] ,-1);
	}

}
int main() {
	ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
	int n, m, k;
	//cin >> n >> m >> k;
	n = read(), m = read(), k = read();
	for (int i = 1; i < n; i++) {
		int x, y;
		//cin >> x >> y;
		x = read(), y = read();
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs1(1, 0);
	dfs2(1,1);
	build(1, 1, n);
	for (int i = 1; i <= m; i++) {
		int x, y;
		//cin >> x >> y;
		x = read(), y = read();
		p[x].push_back(y);
	}

	for (int i = 1; i <= k; i++) {
		int a, b;
		//cin >> a >> b;
		a = read(), b = read();
		q[a].push_back({ b,i });//类似taryan算法的求值,i是第几个问题
	}
	dfs3(1, 0);
	for (int i = 1; i <= k; i++) cout << ans[i] << '\n';
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值