列表

详情


NC25555. 华华和奕奕的旅行

描述

华华和奕奕来到了C城市旅行。在C城市观光多天后他们发现C城市经常断水,于是热心的他们决定研究一下断水的原因。经过观察,他们发现C城市有n个地区,每个地区每天都有各自的产水量w[i]以及用水量c[i],每个地区产的水可以供本地区使用,也可以向它管辖的地区输送水。一个地区可以管辖多个地区,但是一个地区只能被其中一个地区管辖,且1号地区不被任何地区管辖。换句话说,管辖关系构成一棵有根树,且树根为1。通过长时间的研究他们发现了n个地区的管辖关系。但每个地区的产水量总是不停变化,使得研究过程过于困难。于是他们决定写程序来解决。
有Q次操作:
若op==1,输入a,b,表示w[a]=w[a]+b。
若op==2,输入a,b,表示w[a]=w[a]-b。
若op==3,输出是否每个地区都不缺水。

输入描述

第一行输入n
接下来n-1行,每行输入x,y,表示x管辖y。
接下来一行输入n个数表示每个地区的产水量,即w[i]。
接下来一行输入n个数表示每个地区的用水量,即c[i]。
输入Q
接下来Q行
每行先输入op,若op!=3,输入a,b
1<=n,Q<=1e5,0<=w[i],c[i]<=1e9
1<=x,y<=n,1<=a<=n,1<=b<=1e9
数据保证w[i]不会减为负数,且op==1的情况不超过500次

输出描述

对于每次询问,若所有地区都不缺水,输出"YES"
否则,输出"NO"

示例1

输入:

7
1 2
1 3
2 4
3 5
5 6
5 7
8 5 3 2 1 1 2
1 4 4 5 0 1 1
8
3
2 2 4
2 4 2
3
1 1 1
3
1 3 1
3

输出:

YES
NO
NO
YES

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 823ms, 内存消耗: 12892K, 提交时间: 2019-05-17 22:11:37

#include <bits/stdc++.h>
using namespace std;

const size_t maxn = 1 << 17;
size_t father[maxn], fa[maxn];
vector<size_t> son[maxn];
int64_t w[maxn], c[maxn], a[maxn], b[maxn];

void find(size_t u, int64_t x) {
	if (!u) {
		b[0] -= x;
		return;
	}
	int64_t mi = min(x, b[fa[u]]);
	b[fa[u]] -= mi;
	x -= mi;
	if (x) {
		find(father[fa[u]], x);
		fa[u] = fa[father[fa[u]]];
	}
}

int main() {
	size_t n;
	cin >> n;
	for (size_t i = 1; i != n; ++i) {
		size_t x, y;
		cin >> x >> y;
		son[x].emplace_back(y);
		father[y] = x;
	}
	vector<size_t> bfs(1, 1);
	for (size_t i = 0; i != bfs.size(); ++i) for (const auto& v : son[bfs[i]]) bfs.emplace_back(v);
	reverse(bfs.begin(), bfs.end());
	for (size_t i = 1; i <= n; ++i) cin >> w[i];
	for (size_t i = 1; i <= n; ++i) cin >> c[i];
	for (size_t i = 1; i <= n; ++i) a[i] = w[i] - c[i];
	bool check;
	auto build = [&] () {
		for (size_t i = 1; i <= n; ++i) b[i] = a[i], fa[i] = i;
		b[0] = 0;
		for (const auto& u : bfs) if (b[u] < 0) {
			b[father[u]] += b[u];
			b[u] = 0;
		}
		// cout << "b : ";
		// for (size_t i = 0; i <= n; ++i) cout << b[i] << ' ';
		// cout << endl;
		check = b[0] < int64_t(0);
	};
	build();
	size_t Q;
	cin >> Q;
	while (Q--) {
		int op;
		cin >> op;
		if (op == 1) {
			size_t A;
			int64_t B;
			cin >> A >> B;
			a[A] += B;
			build();
		}
		if (op == 2) {
			size_t A;
			int64_t B;
			cin >> A >> B;
			a[A] -= B;
			if (check) continue;
			find(A, B);
			check = b[0] < int64_t(0);
		}
		if (op == 3) {
			cout << (check ? "NO" : "YES") << endl;
		}
	}
}

C++11(clang++ 3.9) 解法, 执行用时: 1498ms, 内存消耗: 8700K, 提交时间: 2019-05-28 09:52:16

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 100005;
int n, num, q, cnt, p[N], f[N], fa[N], c[N], h[N], e[N], pre[N];
ll w[N], a[N];
void add(int x, int y){ e[++num]=y, pre[num]=h[x], h[x]=num;}
int find(int x){ return f[x]==x?x:f[x]=find(f[x]);}
void dfs(int u){
	p[++cnt]=u;
	for(int i=h[u]; i; i=pre[i]) dfs(e[i]);
}
void rebuild(){
	for(int i=1; i<=n; ++i) a[i]=c[i];
	for(int i=n; i; --i){
		int u=p[i];
		if(a[u]>w[u]) a[f[u]=fa[u]]+=a[u]-w[u]; else f[u]=u;
	}
	for(int i=1; i<=n; ++i){
		int u=p[i];
		f[u]=f[f[u]];
	}
}
int main() {
	scanf("%d", &n);
	for(int i=1, x, y; i<n; ++i) scanf("%d%d", &x, &y), add(x, y), fa[y]=x;
	for(int i=1; i<=n; ++i) scanf("%lld", w+i);
	for(int i=1; i<=n; ++i) scanf("%d", c+i);
	dfs(1), rebuild();
	scanf("%d", &q);
	while(q--){
		int opt, x, y;
		scanf("%d", &opt);
		if(opt==3) puts(a[1]>w[1]?"NO":"YES");
		else{
			scanf("%d%d", &x, &y);
			if(opt==1) w[x]+=y, rebuild();
			else{
				w[x]-=y;
				if(f[x]!=x) a[x=find(x)]+=y;
				while(x!=1 && a[x]>w[x])
					f[x]=fa[x], a[find(x)]+=a[x]-w[x], x=f[x];
			}
		}
	}
	return 0;
}

上一题