题目:
题意:
有一颗树,你可以断开点(第一个随便断,以后只能是和已经断开的点相临的点),每个点有权值,断开之后,经一条边和两条边可以到达的节点权值加一,问到最后出现过的最大的权值。
分析:
为啥断开之后就剩下的点就不算相邻了呢。。。(原题说的是掉线,可是掉线之后线依然在啊。。。),其实题意好像是掉线之后就断开了。
拿这不就简单了,不管从谁开始断,都会分成几个子树,然后子树又只能从根开始断,这样就有,选作根的点权值为原权值,剩下的和它相邻的权值+1,剩下的权值+2。
然后就随便处理一下就好了,为了方便理解,列出情况:
1.只有一个ma(ma表示最大的点的权值){
所有ma-1都与它相邻或没有ma-1
ans=ma
剩下的情况
ans=ma+1
}
2.有多个ma{
所有ma都与其中一个相邻
ans=ma+1
剩下的情况
ans=ma+2
}
最后是代码:
#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; }