CF796C Bank Hacking

 

 

 

 

 

题意:给定一棵树,每个节点上有一个银行,最初所有银行全部在线,有一只狗想要打下所有银行(没错是狗),每个银行都有一个安全值,狗的电脑的值必须大于等于所攻下银行的安全值,且每打下一个银行后和它距离为1和2的点的安全值都会在原来的基础上加1,求如果这只超级赛亚狗想要打下所有的银行所需的电脑的值的最小值。

思路:由于每次操作都会导致相邻的点的安全值加1,所以我们(假设我们是狗,呸,我才不是狗)在最开始是一定先拿安全值最大的点开刀,防止他通过与它相邻的点安全值进一步增大。

先举个例子,我们设如图7点的权值为Max,其余为Max-1,从7点开刀,那么最终影响答案的节点是4,5,3因为最终他们的值为Max+1。

我们再设7点权值为Max,1,6为Max-1,其余为Max-2,我们发现,我们想打下每个节点的权值都是Max.

不难发现,若只有一个最大值节点,那么与它直接相连的节点的安全值都会在原来基础上加1,其余加2,所以我们只需要查找Max-1的位置即可,若所有Max-1都与Max相连,那么答案就是Max,若有Max-1节点在其他地方,则为Max+1,如果连Max-1的点都没有,就是Max。

 

再来一个例子考虑有多个Max的情况,上面的结论依旧成立,所以我们需要判断所有Max是否都连在同一个点上,或者都连在其中一个Max上,这样答案就一定是Max+1,否则就是Max+2;

假设上图1,3,4,2号为Max,则打下3,4所需的值就是Max+1,答案即为Max+1。

假设上图4,3,2号位Max,我们此时就要注意不能从Max开始,而应从1号开始,答案仍为Max+1.

假设1,6为Max,此时打下六号所需值为Max+2,答案即为Max+2;

总结:

1.只有一个Max找Max-1位置,都与Max直接相连则答案为Max,否则为Max+1.

2.有多个Max找Max,都连在一起则为Max+1,否则为Max+2

最后注意细节计算即可:

上代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<vector>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N=5e6+10;
 8 int Head[N],tot;
 9 ll val[N],totm,totc;
10 struct Node{
11     int next,to;
12 }edge[N];
13 ll MAX(ll a,ll b){
14     return a>b?a:b;
15 }
16 void Add(int x,int y){ 
17     edge[++tot].to=y;
18     edge[tot].next=Head[x];
19     Head[x]=tot;
20 }
21 int main(){
22     int n;
23     ll Max=-2147483646,t;
24     scanf("%d",&n);
25     for(int i=1;i<=n;++i){
26         scanf("%lld",&val[i]);
27         if(val[i]>Max){  //寻找最大值并找到一个Max位置 
28             Max=val[i];
29             t=i;
30         }
31     }
32     for(int i=1;i<=n;++i){  //计算Max,Max-1数量 
33         if(val[i]==Max) totm++;
34         if(val[i]==Max-1) totc++;
35     }
36     for(int i=1;i<n;++i){
37         int a,b;
38         scanf("%d%d",&a,&b);
39         Add(a,b);Add(b,a);
40     }
41     if(totm==1){   //Max只有一个 
42         if(!totc){ //无Max-1直接输出 
43             printf("%d\n",Max);
44             return 0;
45         }
46         else{
47             int now=0;
48             for(int i=Head[t];i;i=edge[i].next){
49                 int v=edge[i].to;
50                 if(val[v]==Max-1) now++;   //判断Max-1是否都连在Max上 
51             }
52             if(now==totc){
53                 printf("%d\n",Max);
54                 return 0;
55             }
56             else{
57                 printf("%d\n",Max+1);
58                 return 0; 
59             }
60         }
61     }
62     if(totm>=2){  //多个Max 
63         for(int i=1;i<=n;++i){   //看所有Max是否连于一点 
64             int cnt=0;
65             for(int j=Head[i];j;j=edge[j].next){
66                 int v=edge[j].to;
67                 if(val[v]==Max) cnt++;
68             }
69             if(val[i]!=Max&&cnt==totm){ //两种情况 
70                 printf("%d\n",Max+1);
71                 return 0;
72             }
73             if(val[i]==Max&&cnt==totm-1){
74                 printf("%d\n",Max+1);
75                 return 0;
76             }
77         }
78     }
79     printf("%d\n",Max+2);  //都不满足输出Max+2 
80     return 0;
81 }
View Code

 

posted @ 2020-04-30 11:49  19502-李嘉豪  阅读(183)  评论(0编辑  收藏  举报