题意:
给你一个树状图的银行结点, 你要攻击所有的银行, 每个银行有一个权值wi, 攻击这个银行你需要能力值为wi, 你攻击一个银行,那么这个银行相邻的银行的权值+1,间接相邻 的银行权值也加1, 这里的间接相邻指的是: 如果i 和j 间接相邻,那么必然存在一个没被攻击的k 使得i与k 相邻, k 与j 相邻。
思路:
找找规律便发现:
如果从某个结点i 开始 攻击的话,那么和i 直接相邻的点 需要w+1的能力值, 其余的都是 w+2
那么 我们就可以分类讨论了:
假设所有结点权值最大值是m
1.如果答案是w: 那么只能是只有一个m,并且所有的m-1 与m 相邻。
2.如果答案是w+1:那么必须存在一个点 连接着所有的m,并且必须从这个点开始攻击。
3. 其余情况均是w+2
如果不分类讨论的话 直接拿一个set 模拟这个过程也可以:
#include <bits/stdc++.h>
#define Siz(x) (int)x.size()
using namespace std;
const int maxn = 3e5 + 7;
const int oo = 1e9 + 7;
int a[maxn];
vector<int>g[maxn];
int m,n;
vector<int>v[2];
int solve(){
int sum1 = 0,sum0 = 0;
for (int i = 1; i <= n; ++i){
if (a[i] == m){
v[1].push_back(i);
sum1++;
}
else if (a[i] == m-1){
v[0].push_back(i);
sum0++;
}
}
if (sum1 == 1){
int sum = 0;
int p = v[1][0];
for (int i = 0; i < Siz(g[p]); ++i){
int w = g[p][i];
if (a[w] == m-1) ++sum;
}
if (sum == sum0) return m;
return m+1;
}
bool ok = 0;
for (int i = 1; i <= n; ++i){
int sum = 0;
if (a[i] == m) ++sum;
for (int j = 0; j < Siz(g[i]); ++j){
int w = g[i][j];
if (a[w] == m)++sum;
}
if (sum == sum1) {
ok = 1;
break;
}
}
if (ok) return m + 1;
return m+2;
}
int main(){
scanf("%d",&n);
m = -oo;
for (int i = 1; i <= n; ++i) {
scanf("%d",a+i);
m = max(m,a[i]);
}
for (int i = 1; i < n; ++i){
int u,v;
scanf("%d %d",&u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
int ans = solve();
printf("%d\n",ans);
return 0;
}
/**
5
1 2 3 4 5
1 2
2 3
3 4
4 5
5
7
38 -29 87 93 39 28 -55
1 2
2 5
3 2
2 4
1 7
7 6
93
5
1 2 7 6 7
1 5
5 3
3 4
2 4
8
**/