题目链接:CodeForces-796C
题目描述:
Although Inzane successfully found his beloved bone, Zane, his owner, has yet to return. To search for Zane, he would need a lot of money, of which he sadly has none. To deal with the problem, he has decided to hack the banks.
There are n banks, numbered from 1 to n. There are also n - 1 wires connecting the banks. All banks are initially online. Each bank also has its initial strength: bank i has initial strength ai.
Let us define some keywords before we proceed. Bank i and bank j are neighboring if and only if there exists a wire directly connecting them. Bank i and bank j are semi-neighboring if and only if there exists an online bank k such that bank i and bank k are neighboring and bank k and bank j are neighboring.
When a bank is hacked, it becomes offline (and no longer online), and other banks that are neighboring or semi-neighboring to it have their strengths increased by 1.
To start his plan, Inzane will choose a bank to hack first. Indeed, the strength of such bank must not exceed the strength of his computer. After this, he will repeatedly choose some bank to hack next until all the banks are hacked, but he can continue to hack bank x if and only if all these conditions are met:
1.Bank x is online. That is, bank x is not hacked yet.
2.Bank x is neighboring to some offline bank.
3.The strength of bank x is less than or equal to the strength of Inzane’s computer.
Determine the minimum strength of the computer Inzane needs to hack all the banks.
输入
The first line contains one integer n (1 ≤ n ≤ 3·105) — the total number of banks.
The second line contains n integers a1, a2, …, an ( - 109 ≤ ai ≤ 109) — the strengths of the banks.
Each of the next n - 1 lines contains two integers ui and vi (1 ≤ ui, vi ≤ n, ui ≠ vi) — meaning that there is a wire directly connecting banks ui and vi.
It is guaranteed that the wires connect the banks in such a way that Inzane can somehow hack all the banks using a computer with appropriate strength.
输出
Print one integer — the minimum strength of the computer Inzane needs to accomplish the goal.
题目大意:
一共有n个结点,有n-1条边连接,每个节点都有一个值a [ i ]。如果i和j之间有一条边,视作相邻;如果i和j之间有一个没有被攻击的结点,视作半相邻。当一个结点被攻击时,和它相邻或半相邻的点的值加1.选择一个结点开始攻击,每次只能攻击与已被攻击结点相邻的结点。求得所有结点都攻击完后,所有情况中最大值的最小值ans。
思路:
1).n-1条边连接n个结点,所以本题不存在环。对于每一个点i,从已被攻击点逼近它的路只有一条,那么它的值最多增加2
2).我们所求的ans一定大于等于所有结点中的最大值MAXI,并且小于等于最大值MAXI+2,所以答案只有MAXI,MAXI+1或MAXI+2.
3).为了尽可能使所有结点最终值小,一定选择从值为MAXI的结点开始攻击(如果不从MAXI开始,那么最小值必定大于MAXI,不符合一些情况的最优解)
对答案进行分类:
MAXI:
序列中只有一个值为MAXI的结点,并且所有的MAXI-1的结点都与该结点直接相邻;
MAXI+1:
情况一:只有一个MAXI,并且存在与MAXI距离大于等于2的MAXI-1;
情况二:有多个MAXI,并且其中一个MAXI与剩下的MAXI都直接相邻;
MAXI+2:
不符合MAXI和MAXI+1条件的,ans都是MAXI+2;
按照以上规律得出代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
long n;
vector<long> wire[300010];
long bank[300010];
int main()
{
long ct1,ct2,M,m,s1,s2,ads,flag,Flag;
while(~scanf("%ld",&n))
{
ct1=0;
ct2=0;
M=-1e9-1;
m=-1e9-1;
for(int i=1;i<=n;++i)
{
scanf("%ld",&bank[i]);
if(bank[i]>M)
{
m=M;
M=bank[i];
ct2=ct1;
ct1=1;
ads=i;
}
else if(bank[i]==M)++ct1;
else
{
if(bank[i]==m)++ct2;
else if(bank[i]>m)
{
m=bank[i];
ct2=1;
}
}
wire[i].clear();
wire[i].push_back(i);
}
for(int i=1;i<=n-1;++i)
{
scanf("%ld %ld",&s1,&s2);
wire[s1].push_back(s2);
wire[s2].push_back(s1);
}
if(ct1==1)
{
if(m!=M-1)printf("%ld\n",M);
else
{
for(int i=0;i<wire[ads].size();++i)
if(bank[wire[ads][i]]==m)--ct2;
if(ct2)printf("%ld\n",M+1);
else printf("%ld\n",M);
}
}
else
{
Flag=0;
for(int i=1;i<=n;++i)
{
flag=0;
for(int j=0;j<wire[i].size();++j)
{
if(bank[wire[i][j]]==M)++flag;
}
if(flag==ct1)
{
Flag=1;
break;
}
}
if(Flag)
printf("%ld\n",M+1);
else
printf("%ld\n",M+2);
}
}
return 0;
}
小结:
水题一枚,注意一下分类不要写错就可以了。