题解 P7162 【[COCI2020-2021#2] Sjekira】
两种做法。一种
这个题显然考虑贪心。每次从连通块大小不为
第二种做法更有意思一点。我们尝试把贪心得到的值写成一个表达式:
证明如下:考虑任意一棵子树
直接计算此式即可。时间复杂度为
此处只贴上第一种做法的代码,第二种这么简单大家都会写吧(
#include<cstdio>
#include<vector>
#include<algorithm>
typedef long long ll;
int cnt=0;
std::vector<int> vec[100005];
int maxn[100005],vis[100005],fa[100005],id[100005];
inline int read() {
register int x=0,f=1;register char s=getchar();
while(s>'9'||s<'0') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
return x*f;
}
inline int max(const int &x,const int &y) {return x>y? x:y;}
inline int find(int x) {return x==fa[x]? x:fa[x]=find(fa[x]);}
inline bool cmp(int x,int y) {return maxn[x]<maxn[y];}
int main() {
int n=read(); ll ans=0;
for(register int i=1;i<=n;++i) maxn[i]=read(),fa[i]=id[i]=i;
std::sort(id+1,id+1+n,cmp);
for(register int i=1;i<n;++i) {int x=read(),y=read(); vec[x].push_back(y); vec[y].push_back(x);}
for(register int i=1;i<=n;++i) {
int x=id[i]; vis[x]=1;
for(register int k=0;k<vec[x].size();++k) {
int y=vec[x][k]; if(!vis[y]) continue;
int fx=find(x),fy=find(y);
if(fx!=fy) {
ans+=maxn[fx]+maxn[fy];
maxn[fx]=max(maxn[fx],maxn[fy]);
fa[fy]=fx;
}
}
}
printf("%lld\n",ans);
return 0;
}