#C. Ki

该文描述了一个以1为根的树形结构问题,其中每个节点有一个计数器,初始值为0。文章提出了Q次操作,每次操作会增加某个节点p_i的子树中所有点的计数器值x_i。解决方案是使用深度优先搜索(DFS)将增加的数值逐层向下传递到子节点,最终输出每个节点的计数器最终值。

Description

给出一棵以1为根的树,有N个点,每个点上有一个计数器,初始0

接下来Q次操作,每次操作将p_i的子树中所有点的计数器增加x_i,输出最后每个点的计数器值

Format

Input

第一行给出N,Q

接下来N-1行描述这个树

再接下来Q行,每行给出Pi,Xi

2<=N<=2e5

1<=Q<=2e5

xi<=1e4

Output

如题

Samples

输入数据 1

4 3

1 2

2 3

2 4

2 10

1 100

3 1

输出数据 1

100 110 111 110


思路:

每次操作是给以x为根的子树统一加一个数值

于是将增加的数值打在x这个点上,并在今后的dfs遍历中传递下去加给x的每个子结点,一直这样递归下去,直到叶子结点为止


代码:

将以下内容改成一个内容 要将现有代码改成使用PID实现Buck回路,并将其分文件呈现,我们需要对代码进行模块化处理。以下是分文件的实现方式: --- ### 1. **main.c** 这是主程序文件,负责初始化和循环逻辑。 ```c #include "stm32f10x.h" #include "bsp_usart.h" #include "tim.h" #include "key.h" #include "led.h" #include "adc1.h" #include "OLED_Data.h" #include "OLED.h" #include "bsp_GeneralTim.h" #include "pid.h" float pid_voltage; float Vout_set = 12.0f; // 目标输出电压12V float Vout_actual, Iout_actual; int main(void) { TIM_Advance_Init(); Key_Config(); LED_GPIO_Config(); USART_Config(); ADCX_Init(); GENERAL_TIM_Init(); OLED_Init(); OLED_Clear(); PID_Init(&pid_voltage, 0.8f, 30.0f, 0.0001f, 1.0f); // Ts=100us while (1) { // 获取ADC采样值(假设已校准) Vout_actual = ADC_GetVoltage(); // 调用ADC模块获取电压 Iout_actual = ADC_GetCurrent(); // 调用ADC模块获取电流 // PID计算(电压环) float duty = PID_Update(&pid_voltage, Vout_set, Vout_actual); // 更新PWM占空比(限制在10%-90%) TIM_SetDuty(duty); } } ``` **解释:** - 主程序中调用了`PID_Update`函数来计算新的PWM占空比。 - `TIM_SetDuty`函数用于设置PWM占空比。 --- ### 2. **pid.c** 这是PID控制器的实现文件。 ```c #include "pid.h" void PID_Init(PID_HandleTypeDef *hpid, float kp, float ki, float kd, float ts) { hpid->Kp = kp; hpid->Ki = ki; hpid->Kd = kd; hpid->Ts = ts; hpid->PrevError = 0.0f; hpid->Integral = 0.0f; } float PID_Update(PID_HandleTypeDef *hpid, float setpoint, float process_value) { float error = setpoint - process_value; hpid->Integral += error * hpid->Ts; float derivative = (error - hpid->PrevError) / hpid->Ts; float output = hpid->Kp * error + hpid->Ki * hpid->Integral + hpid->Kd * derivative; hpid->PrevError = error; return output; } ``` **解释:** - `PID_Init`函数初始化PID控制器的参数。 - `PID_Update`函数据当前误差计算新的控制输出。 --- ### 3. **pid.h** 这是PID控制器的头文件。 ```c #ifndef __PID_H #define __PID_H typedef struct { float Kp; float Ki; float Kd; float Ts; float PrevError; float Integral; } PID_HandleTypeDef; void PID_Init(PID_HandleTypeDef *hpid, float kp, float ki, float kd, float ts); float PID_Update(PID_HandleTypeDef *hpid, float setpoint, float process_value); #endif ``` **解释:** - 定义了PID控制器的结构体`PID_HandleTypeDef`。 - 提供了`PID_Init`和`PID_Update`函数的声明。 --- ### 4. **tim.c** 这是定时器模块的实现文件。 ```c #include "tim.h" void TIM_SetDuty(float duty) { if (duty > 0.9f) duty = 0.9f; if (duty < 0.1f) duty = 0.1f; TIM_Advance_Impulse = (uint16_t)(duty * TIM_Advance_Period); TIM1->CCR1 = TIM_Advance_Impulse; } ``` **解释:** - `TIM_SetDuty`函数用于设置PWM占空比,并限制其范围在10%-90%之间。 --- ### 5. **adc1.c** 这是ADC模块的实现文件。 ```c #include "adc1.h" float ADC_GetVoltage(void) { return ADC_ConvertedValue[0] * 3.3f / 4096 * (10 + 2) / 2; // 分压比计算 } float ADC_GetCurrent(void) { return (ADC_ConvertedValue[1] * 3.3f / 4096 - 1.65f) / 0.1f / 20; // 运放放大20倍 } ``` **解释:** - `ADC_GetVoltage`函数从ADC采样值中提取电压。 - `ADC_GetCurrent`函数从ADC采样值中提取电流。 --- ### 6. **adc1.h** 这是ADC模块的头文件。 ```c #ifndef __ADC1_H #define __ADC1_H #include "stm32f10x.h" float ADC_GetVoltage(void); float ADC_GetCurrent(void); #endif ``` **解释:** - 提供了`ADC_GetVoltage`和`ADC_GetCurrent`函数的声明。 --- ### 7. **中断函数 (stm32f10x_it.c)** 这是中断服务程序的实现文件。 ```c #include "stm32f10x_it.h" #include "adc1.h" void ADC_IRQHandler(void) { if (ADC_GetITStatus(ADC_X, ADC_IT_EOC) == SET) { ADC_ConvertedValue[0] = ADC_GetConversionValue(ADC_X); ADC_ConvertedValue[1] = ADC_GetConversionValue(ADC_X); // 假设多通道转换 } ADC_ClearITPendingBit(ADC_X, ADC_IT_EOC); } ``` **解释:** - 在中断服务程序中更新`ADC_ConvertedValue`数组。 --- ###
05-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值