2019牛客暑期多校训练营(第八场) I Inner World(dfs序+线段树)

链接:https://ac.nowcoder.com/acm/contest/888/I
来源:牛客网
 

题目描述

Gromah and LZR are transfered to a forest, maybe it is the inner world of the great tomb. Initially, there are nn_{}n​ rooted trees numbered from 11_{}1​ to nn_{}n​ with size 11_{}1​ in the forest. For each tree, the only node is the root and labeled with 11_{}1​.

After a while, here comes a farmer, and the farmer gives them mm_{}m​ planting tasks, each can be described by a tuple (u,v,l,r)(u,v,l,r)_{}(u,v,l,r)​, which means to add a labeled node vv_{}v​ for all trees numbered from ll_{}l​ to rr_{}r​, and their parent nodes are the nodes labeled with uu_{}u​ for each tree.

After finishing the planting tasks one by one, the farmer will give them qq_{}q​ querying tasks, each can be described by a tuple (x,l,r)(x,l,r)_{}(x,l,r)​, which means to query the sum of sizes of subtrees whose roots are the nodes labeled with xx_{}x​ among the trees numbered from ll_{}l​ to rr_{}r​. Specially, if there isn't a node labeled with xx_{}x​ in a tree, the size of subtree xx_{}x​ is regarded as 00_{}0​.

If they complete all tasks perfectly, the farmer will help them pass the final level.

Please help them handle these tasks.

输入描述:

 

The first line contains two positive integers n,mn,m_{}n,m​, denoting the number of trees in the inner world and the number of planting tasks.

Following mm_{}m​ lines each contains four positive integers u,v,l,ru,v,l,r_{}u,v,l,r​, denoting a planting task (u,v,l,r)(u,v,l,r)_{}(u,v,l,r)​.

The next line contains one positive integer qq_{}q​, denoting the number of querying tasks.

Following qq_{}q​ lines each contains four positive integers x,l,rx,l,r_{}x,l,r​, denoting a querying task (x,l,r)(x,l,r)_{}(x,l,r)​.

1≤n,m,q≤300000,1≤u,x≤m+1,2≤v≤m+1,1≤l≤r≤n1\le n,m,q \le 300000, 1 \le u,x \le m + 1, 2 \le v \le m + 1, 1 \le l \le r \le n1≤n,m,q≤300000,1≤u,x≤m+1,2≤v≤m+1,1≤l≤r≤n

For each planting task, It is guaranteed that the label vv_{}v​ is unique among all vv_{}v​s, and the trees numbered from ll_{}l​ to rr_{}r​ all have a node labeled with uu_{}u​ right before handling this task.

输出描述:

Output qq_{}q​ lines, each contains one non-negative integer denoting the answer to corresponding query task.

示例1

输入

复制

4 3
1 2 1 2
1 3 2 4
3 4 2 3
2
1 1 4
3 1 4

输出

复制

11
5

说明

Four trees are 1-2, 1(-2)-3-4, 1-3-4, 1-3.

In the four trees, sizes of subtrees 1 are 2,4,3,2, so the answer to the first query task is 2+4+3+2=11, while the sizes of subtrees 3 are 0,2,2,1 and the answer to the second query task is 0+2+2+1=5.

        有n棵树,有m个操作,每次操作将l,r区间内的u节点上加一个v,保证每次操作u必定存在

        然后有q个询问,每次问x,l,r,求l,r树木区间内的x的子树的数量和。

        因为题目保证v不一样的,所以我们先将所有的操作当成一棵树的操作,进行dfs序,获得父子树关系。然后按照dfs序列遍历一边。每次到一个点,用线段树在区间l,r加上一,这样我们要求某一个节点x的子树在l,r区间内的子节点数量和,就相当于rt[x]时的l,r区间总和减去lt[x]时的l,r区间总和就好了。不明白的私聊留言即可。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 300005;
int n, m, L[maxn], R[maxn], cnt = 0;
int pos[maxn], lt[maxn], rt[maxn];
LL c[maxn * 4], lazy[maxn * 4];
vector<int>G[maxn];
struct node { int p, l, r; };
vector<node>q[maxn];
LL ans[maxn];
void dfs(int u) {
	pos[lt[u] = ++cnt] = u;
	for (auto v : G[u])dfs(v);
	rt[u] = cnt;
}
void push_down(int x, int l, int r) {
	int mid = (l + r) / 2;
	c[x << 1] += lazy[x] * (mid - l + 1);
	c[x << 1 | 1] += lazy[x] * (r - mid);
	lazy[x << 1] += lazy[x];
	lazy[x << 1 | 1] += lazy[x];
	lazy[x] = 0;
}
void update(int x, int l, int r, int left, int right) {
	if (left <= l && right >= r) {
		c[x] += r - l + 1;
		lazy[x] += 1;
		return;
	}
	push_down(x, l, r);
	int mid = (l + r) / 2;
	if (left <= mid)
		update(x << 1, l, mid, left, right);
	if (right > mid)
		update(x << 1 | 1, mid + 1, r, left, right);
	c[x] = c[x << 1] + c[x << 1 | 1];
}
LL query(int x, int l, int r, int left, int right) {
	if (left <= l && right >= r) return c[x];
	push_down(x, l, r);
	int mid = (l + r) / 2;
	LL ans = 0;
	if (left <= mid)
		ans += query(x << 1, l, mid, left, right);
	if (right > mid)
		ans += query(x << 1 | 1, mid + 1, r, left, right);
	return ans;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int u, v, l, r;
		cin >> u >> v >> l >> r;
		G[u].push_back(v);
		L[v] = l; R[v] = r;
	}
	L[1] = 1; R[1] = n;
	dfs(1);
	int qu; cin >> qu;
	for (int i = 1; i <= qu; i++) {
		int x, l, r;
		cin >> x >> l >> r;
		q[lt[x] - 1].push_back(node{ -i,l,r });
		q[rt[x]].push_back(node{ i,l,r });
	}
	for (int i = 1; i <= cnt; i++) {//按dfs序列遍历
		update(1, 1, n, L[pos[i]], R[pos[i]]);
		for (auto v : q[i]) {
			int t = abs(v.p), op = v.p / t;
			ans[t] += query(1, 1, n, v.l, v.r) * op;
		}
	}
	for (int i = 1; i <= qu; i++) 
		printf("%lld\n", ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/chenshibo17/article/details/99544799