[CF796C] Bank Hacking

題目

給定一棵帶點權樹,選出一個最佳的根節點,使得根節點的點權不變,它的兒子點權加\(1\),其他點點權加\(2\),並使最大點權最小,輸出這個最小的最大點權。(我愛死洛谷上的這個翻譯了!本來老長的題設精簡成了這麼簡單易懂的樣子)c++

解說

一眼看去是否是樹形\(DP\)?太複雜了不想寫啊,能寫別的是不可能寫樹形\(DP\)的,這輩子都不可能寫樹形\(DP\)的。這麼簡單的題意,確定有別的寫法吧?
確實有!
總感受這個題沒有代碼不太好說,直接看下面代碼的註釋吧……數組

代碼

#include<bits/stdc++.h>
using namespace std;
#define v e[j].to//注意這裏,下面的v都是e[j].to
const int maxn=300000+3;
int a[maxn];
struct edge{
	int next,to;
}e[2*maxn];
int n,ans,fin,tot,head[maxn];//fin表明最終答案
map<int,int> m;//鍵爲點權,值爲編號
//由於權值有負數不能用數組
void Add(int a,int b){
	e[tot].to=b;
	e[tot].next=head[a];
	head[a]=tot;
	tot++;
}
int main(){
	ans=-1000000000;//找最大值
	tot=1;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		ans=max(ans,a[i]);
		m[a[i]]++;//記錄權值出現了幾回
	}
	for(int i=1;i<=n-1;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		Add(x,y);
		Add(y,x);
	}
	fin=ans+2;//若是沒有更小答案fin就是ans+2
	for(int i=1;i<=n;i++){
		bool judge=0;
		for(int j=head[i];j;j=e[j].next){
			m[a[v]]--;//記錄兒子的權值
			if(a[v]==ans) judge=1;//記錄兒子裏是否有最大值
		}
		if(!m[ans]) fin=ans+1;//這說明全部的最大值都在兒子裏,因此fin=ans+1
		if(m[ans]==1&&a[i]==ans){//這說明最大值在根節點
			if(judge) fin=ans+1;//最大值在根節點的狀況下兒子裏還有最大值,確定兒子由於加了1較大
			else if(m[ans-1]) fin=ans-1+2;//兒子裏面沒有最大值了可是兒子以外有權值爲ans-1的節點權值+2
                        //因此這裏爲了看的明白沒有直接寫ans+1
			else{
				fin=ans;//只有根節點是最大值了,沒有別的能夠超過
				break;//記得break!!!在這裏栽了兩次
                                //爲何要break?這已是最佳答案了,以後再計算會再變回更大的值
			}
		}
		for(int j=head[i];j;j=e[j].next) m[a[v]]++;
	}
	printf("%d",fin);
}

幸甚至哉,歌以詠志。spa

相關文章
相關標籤/搜索