P11855 [CSP-J2022 山东] 部署

题目传送门
水题!
第一眼以为是根号分治。
由于题目的要求是全部 m m m 次命令执行完之后才询问,这意味着可以像差分一样最后统一跑一遍求出答案。
命令 2,我们可以打标记处理, d d a x dda_x ddax 表示所有与点 x x x 相邻的点需要增加的数量,最后全部加上就行了。

for(int x=1;x<=n;x++){
		for(int i=0;i<a[x].size();i++){
			int y=a[x][i];
			ans[x]+=dda[y];
		}
	}

因为是树,只有 n − 1 n-1 n1 条边,时间复杂度 O ( N ) O(N) O(N)
对于命令 1,将点 x x x 的子树全部加上一个数,修改一堆,查询一个,容易想到差分。
还是标记, a d d x add_x addx 表示点 x x x 及其子树需要加上的数,最后从根节点往下 dfs 一遍即可求出。

void dfs(int x,int fa,int sum){
	sum+=add[x];//先更新 sum,当前的点也是子树的一部分
	ans[x]+=sum;
	for(int i=0;i<a[x].size();i++){
		int y=a[x][i];
		if(y==fa)continue;
		dfs(y,x,sum);
	}
}

code

#include<bits/stdc++.h>
#define int long long
#define endl putchar('\n')
using namespace std;
const int N=1e6+5;
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<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
void print(int x){
	if(x<0)putchar('-'),x=-x;
	if(x<10){putchar(x+'0');return;}
	print(x/10);
	putchar(x%10+'0');
}
void putstr(string s){
	for(int i=0;i<s.size();i++)putchar(s[i]);
}
int n,m;
int ans[N];
int d[N];
vector<int>a[N];
int add[N];
int dda[N];
void dfs(int x,int fa,int sum){
	sum+=add[x];
	ans[x]+=sum;
	for(int i=0;i<a[x].size();i++){
		int y=a[x][i];
		if(y==fa)continue;
		dfs(y,x,sum);
	}
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++)ans[i]=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		a[u].push_back(v);
		a[v].push_back(u);
	}
	m=read();
	while(m--){
		int op=read(),x=read(),y=read();
		if(op==2){
			ans[x]+=y,dda[x]+=y;
		}
		else{
			add[x]+=y;
		}
	}
	for(int x=1;x<=n;x++){
		for(int i=0;i<a[x].size();i++){
			int y=a[x][i];
			ans[x]+=dda[y];
		}
	}
	dfs(1,1,0);
	int q=read();
	while(q--){
		int x=read();
		print(ans[x]),endl;
	}
}
### 关于CSP-J 2022 山东赛区的部署相关信息 #### 部署题目概述 在 CSP-J 2022 山东赛区的二轮补赛试题中,T3 的题目名为 **部署**[^4]。该题的核心在于处理一系列命令操作,并根据输入条件执行不同的逻辑判断。 #### 输入描述 题目提供了 `m` 行指令,每行包含三个正整数 `p`, `x`, 和 `y`。具体含义如下: - 当 `p = 1` 时,表示第一种命令; - 当 `p = 2` 时,表示第二种命令。 这些命令可能涉及到数组的操作或其他数据结构的应用,具体的实现细节需结合实际问题背景来分析。 #### 解决思路 由于题目未提供完整的背景信息和目标输出,以下是基于常见竞赛题型的一种推测性解决方法: 假设我们需要维护一个动态的数据集合(如数组或列表),并根据不同类型的命令更新状态,则可以采用以下策略: 1. 使用适当的数据结构存储当前的状态。 2. 对于每条命令,解析其参数并执行对应的操作。 3. 如果存在边界条件或特殊情形(如超出范围、重复值等),应提前检测并妥善处理。 下面是一个伪代码框架示例,用于演示如何处理此类问题: ```cpp #include <iostream> #include <vector> using namespace std; int main() { int m; cin >> m; // 命令总数 vector<int> data(1e5 + 5, 0); // 初始化一个较大的数组作为存储空间 while (m--) { int p, x, y; cin >> p >> x >> y; if (p == 1) { // 执行第一种命令 data[x] += y; // 示例操作:增加某个位置的值 } else if (p == 2) { // 执行第二种命令 data[y] -= x; // 示例操作:减少某个位置的值 } } // 处理最终结果 for (int i = 1; i <= data.size(); ++i) { if (data[i] != 0) { cout << i << " " << data[i] << endl; } } return 0; } ``` 此代码仅为示意用途,实际应用中需要依据具体需求调整逻辑。 --- #### 注意事项 1. 数据规模较大时,建议优化算法复杂度以避免超时风险。 2. 若涉及数值运算,应注意防止溢出现象的发生,可选用更大容量的数据类型(如 `long long`)[^3]。 3. 测试过程中务必覆盖各种极端情况,确保程序鲁棒性和准确性。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值