1. 程式人生 > >[2018.10.18 T1] 艾奇摘蘋果

[2018.10.18 T1] 艾奇摘蘋果

暫無連結

艾奇摘蘋果

【問題描述】

艾奇在遙遠的美洲大陸有一片蘋果樹森林。
聽上去非常不錯的是,蘋果森林每年收成都還不錯。
艾奇摘蘋果的方式非常有趣,由於蘋果樹太高,她常直接折斷樹枝來獲得一大堆(整棵子樹)的蘋果。
艾奇也不想把蘋果樹破壞的太狠,畢竟蘋果樹也不是隻結一年的蘋果。所以她對於一棵樹,至多會折斷一根樹枝。
艾奇不像過去的某魯姓大師,她並沒有那個力氣倒拔蘋果樹,因為一棵樹的根是埋在土裡的。所以她並不能獲得整棵樹的蘋果。
眾所周知,美洲大陸龍捲風賊多。龍捲風既然能摧毀停車場,那麼吹翻一片蘋果森林應該不是什麼難事。所以艾奇養了一些小機器人給艾奇預警龍捲風。
艾奇把這些小機器人放在花上,這樣一來小機器人就能吸收樹的養分工作,但是這也導致了這朵花不能結果。
如果你折斷了一根樹枝,小機器人就會因為沒有養分而狂躁,它們只吃原本和它們屬於同一棵樹上被摘下來的蘋果。如果這些蘋果不夠吃,它們就會把艾奇吃掉。
樹林有點大,艾奇想知道,照她這種收果實的方法,在自己不被吃掉的情況下,至多能收穫多少蘋果呢?

【輸入格式】

輸入檔名為 a p p l e . i n apple. in


第一行兩個整數 n   m n\ m 分別表示這片森林的節點樹和樹枝數量(就是邊的數量)。我們預設一棵樹的根就是這棵樹中編號最小的節點。
接下來 n
n
個整數。
如果該整數為正,那麼表示這個節點結蘋果的數量。
如果該整數為負,那麼表示這個節點養了一個小機器人,它被摘下來要吃的
果子數量。
對於一棵樹的根節點,這個節點的權值可以忽略。
接下來 m m 行,每行兩個整數 i , j i,j 表示 i i j j 在樹上有邊相連。

【輸出格式】

輸出檔名為 a p p l e . o u t apple.out
一行一個整數,表示艾奇至多能收穫多少蘋果。

【輸入樣例 1】

詳見 a p p l e 1. i n apple1.in

【輸出樣例 1】

詳見 a p p l e 1. o u t apple1.out

【資料範圍】

TIM截圖20181018190604.png

題解

d f s dfs 求一棵樹中的最大子樹,把所有樹的最大子樹加到一起。

程式碼

略微卡常

#include<bits/stdc++.h>
using namespace std;
const int M=1e6+5;
int val[M],vis[M],head[M],nxt[M<<1],to[M<<1],n,m,cnt,r,f;
long long ans,sum[M],mx;
char c;
void add(int f,int t){nxt[++cnt]=head[f],head[f]=cnt,to[cnt]=t;}
int read()
{
	for(r=0,f=1;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())r=(r<<1)+(r<<3)+c-'0';
	return r*f;
}
void dfs(int v){vis[v]=1,sum[v]=val[v];for(int i=head[v];i;i=nxt[i])if(!vis[to[i]])dfs(to[i]),sum[v]+=sum[to[i]],mx=max(mx,sum[to[i]]);}
void in()
{
	n=read(),m=read();
	for(int i=1;i<=n;++i)val[i]=read();
	for(int i=1,a,b;i<=m;++i)a=read(),b=read(),add(a,b),add(b,a);
}
void ac(){for(int i=1;i<=n;++i)if(!vis[i])mx=0,dfs(i),ans+=mx;printf("%lld",ans);}
int main(){in(),ac();}