Code Forces 796C Bank Hacking(贪心)
Code Forces 796C Bank Hacking
题目大意
给一棵树,有\(n\)个点,\(n-1\)条边,现在让你决策出一个点作为起点,去掉这个点,然后这个点连接的所有点权值+=1,然后再将这些刚刚加过一的点的相邻的点的权值+=1
也就是说,除了与根节点相邻的点+=1,其余点+=2
然后求最大集合的最小点权
solution
一看是要求最大的的最小值,首先想到的就是二分,显然想到这个目前没有什么卵用,二分是用来卡最佳答案的,所以使用二分的前提是要给它一个范围去选择,那么现在的任务就是去找这个答案的集合,并且希望它是一个有序的集合,这样我们才能二分答案。
预处理时分情况讨论,max,max+1,max+2
- 当\(root\)链接的点只有\(1\)个\(max\):则所有\(max-1\)都和\(root\)相邻或者均为\(max\),更新\(ans = max\),其他的情况就是\(ans = max + 1\)
- 当\(root\)连接的点中有多个\(max\),那么当所有\(max\)和其中一个相邻的时候\(ans=max+1\),剩下的情况,\(ans=max+2\)
代码——pl.()
#include <cstdio>
#include <string>
using namespace std;
const int maxn=3*1e5+10;
int a[maxn];
struct E{
int next;
int to;
E(){
to=next=0;
}
}ed[maxn*2];
int head[maxn];
int tot;
void J(int a,int b){
tot++;
ed[tot].to=b;
ed[tot].next=head[a];
head[a]=tot;
}
int main(){
int n;
scanf("%d",&n);
int ma=-1e9-10;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ma=max(ma,a[i]);
}
int j1,j2;
for(int i=1;i<=n-1;i++){
scanf("%d%d",&j1,&j2);
J(j1,j2);
J(j2,j1);
}
int js1=0,js2=0;//表示ma和ma-1的个数
for(int i=1;i<=n;i++){
if(a[i]==ma)
js1++;
if(a[i]==ma-1)
js2++;
}
if(js1==1){//分情况处理一下
int js=0;
for(int i=1;i<=n;i++)
if(a[i]==ma){
for(int j=head[i];j;j=ed[j].next)
if(a[ed[j].to]==ma-1)
js++;
break;
}
if(js==js2)
printf("%d",ma);
else
printf("%d",ma+1);
}
else{
int js=0;
int zjs=0;
for(int i=1;i<=n;i++){
if(a[i]==ma)
zjs++;
for(int j=head[i];j;j=ed[j].next)
if(a[ed[j].to]==ma)
zjs++;
js=max(js,zjs);
zjs=0;
}
if(js==js1)
printf("%d",ma+1);
else
printf("%d",ma+2);
}
return 0;
}
风吹过,我来过~