速通ACM省铜第十二天 赋源码(Kirei Attacks the Estate)
目录
引言:
Kirei Attacks the Estate
题目分析
逻辑梳理
代码实现
结语:
引言:
今天我们来讲一场div3的E题,说来惭愧,我本来想将这场div3的D也一起发出来的,但我还没想出来怎么打,我感觉E题比D题简单,如图
那么接下来,就进入今天的题目讲解啦————————>
Kirei Attacks the Estate
按照惯例,我们先来看题目
题目分析
题目链接如下Problem - 2114E - Codeforces
不想跳转的可看下图
这个题目虽然很长但其实很简单,就是给你一个树(无环的),根为1,然后计算每个点的最大可能值
值的计算是以这个点开始,可以只选择这个点,也可以往上选择任意个点 ,只需要找到最大的可能值就可以了,如下图的距离
计算完每个点的最大可能值后,将每个节点的最大可能值输出即可
那么,该题的题目分析已经分析完啦,那么就进入逻辑梳理环节
逻辑梳理
这道题的逻辑其实很简单,他已经告诉你树的根节点是1了,那么1的值肯定是固定的了
之后从这个节点往下走,递归,那么如果想要得到下面节点的最大值,是不是他自身的值与他自身的值-他父节点的最小值 这俩个值进行比较,得到最大值就代表他的最大值了
那么我们就需要俩个数组来装
一个数组装这个节点可能的最小值
一个数组装这个节点可能的最大值
然后全部操作完就好啦,接下来就进入代码实现环节啦
代码实现
这题的代码实现也很简单,就是先建个图,我用的是链式前向星建图
然后再用俩个数组ma和mi分别表示每个点能达到的最大和最小值
然后再用vis数组来判断节点是否访问过,因为是无向图,所以不能走回去,要加个数组判断有没有访问过
然后点就用队列来存就好了
最后更新完的ma数组便是需要的结果了
那么,我们来看AC码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;int t;
bool vis[200010];
long long a[200010];
long long ma[200010];
long long mi[200010];
int head[200010];
int nex[400010];
int to[400010];
int cnt;
queue <int> q;void lian(int u, int v)
{cnt++;nex[cnt] = head[u];to[cnt] = v;head[u] = cnt;
}void shu(int x)
{q.push(x);while (!q.empty()){int fu = q.front();vis[fu] = 1;q.pop();for (int i = head[fu]; i; i = nex[i]){int zi = to[i];if (!vis[zi]){ma[zi] = max(a[zi], a[zi] - mi[fu]);mi[zi] = min(a[zi], a[zi] - ma[fu]);shu(zi);}}}
}void solve()
{cnt = 0;memset(head, 0, sizeof(head));memset(vis, 0, sizeof(vis));int n;long long u, v;cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];}for (int i = 1; i < n; i++){int u, v;cin >> u >> v;lian(u, v);lian(v, u);}ma[1] = a[1];mi[1] = a[1];shu(1);for (int i = 1; i <= n; i++){cout << ma[i] << " ";}cout << endl;
}int main()
{cin >> t;while (t--){solve();}return 0;
}
那么,这题就讲解完毕啦
结语:
今日算法讲解到此结束啦,希望对你们有所帮助,谢谢观看,如果觉得不错可以分享给朋友哟。当然也可以关注一下,有什么看不懂的可以评论问哦