题目大意:
给你N个点,每个点的最初权值为a【i】.
现在我们要攻克这N个点,除了第一个点的攻击可以随意选择外,之后选择的攻击的点必须满足:
①这个点没有被攻击过。
②这个点的周围有点是被攻击过的。
③这个点的a【i】此时必须小于等于我们的计算机能力。
让你找到最小的计算机能力,使得攻克掉所有的点。
我们攻击掉一个点i之后,与其直接相连的点(距离为1)的a【i】都会变成a【i】+1.与其距离为2的a【i】也会变成a【i】+1.
思路:
1、根据上述题意要求三个条件,其实简化之后问题就变成了:被攻击的第一个点的a【i】不变,与这个点直接相连的a【i】都要变成a【i】+1.其余的点都变成了a【i】+2.
2、那么我们直接考虑几种极限情况:
设定maxn==max(a【i】)【1<=i<=n】,mx表示maxn的个数,mc表示maxn-1的个数。
①ans==maxn. 当且仅当mx==1.并且这个点的周围的maxn-1的个数==mc.
②ans==maxn+1.如果mx==1.并且这个点的周围的maxn-1的个数<mc.
如果存在一个点u.使得与u直接相连的点和u这个点中maxn的个数==mx.
③其余情况ans==maxn+2.
Ac代码:
#include<stdio.h>
#include<vector>
#include<string.h>
using namespace std;
vector<int >mp[300800];
int a[3500000];
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
int maxn=-1000005000;
for(int i=1;i<=n;i++)maxn=max(maxn,a[i]);
int mx=0,mc=0;
int ans;
int u;
for(int i=1;i<=n;i++)
{
if(a[i]==maxn)mx++,u=i;
if(a[i]==maxn-1)mc++;
}
if(mx==1)
{
int cont=0;
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(a[v]==maxn-1)cont++;
}
if(cont==mc)ans=maxn;
else ans=maxn+1;
printf("%d\n",ans);
}
else
{
int flag=0;
for(int i=1;i<=n;i++)
{
int cont=0;
if(a[i]==maxn)cont++;
for(int j=0;j<mp[i].size();j++)
{
int v=mp[i][j];
if(a[v]==maxn)cont++;
}
if(cont==mx)flag=1;
}
if(flag==1)printf("%d\n",maxn+1);
else printf("%d\n",maxn+2);
}
}
}