Bank Hacking题解

题目:

题意:

  有一颗树,你可以断开点(第一个随便断,以后只能是和已经断开的点相临的点),每个点有权值,断开之后,经一条边和两条边可以到达的节点权值加一,问到最后出现过的最大的权值。

分析:

  为啥断开之后就剩下的点就不算相邻了呢。。。(原题说的是掉线,可是掉线之后线依然在啊。。。),其实题意好像是掉线之后就断开了。

  拿这不就简单了,不管从谁开始断,都会分成几个子树,然后子树又只能从根开始断,这样就有,选作根的点权值为原权值,剩下的和它相邻的权值+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;
}
原文地址:https://www.cnblogs.com/wish-all-ac/p/12805730.html