题 意:现在有一颗染了k种颜色的节点数目为n树,小明想把它染成一种颜色,每个节点颜色的标号为ai . 每次只能把有连边的两个点,一个点染成令外一个点的颜色,所花的代价为ai+aj。求最少的代价
数据范围:
1<=n<=1e5
1<=ai<=1e9
样例输入:
4 //4节点个数
2 3 4 3 //每个节点的颜色编号
1 2 //那两点有边
2 3
3 4
样例输出:
12
思 路:关键点,颜色只有1e5种,枚举每一种颜色, 然后0(1)算出代价。
那么这么在o(1)的时间内算出代价呢。假设枚举到该颜色为x,那么如果该节点不是x
那么就要花费当前节点颜色变化bi+x的代价。可以先求所有节点颜色编号的总和,然后减去颜色为x的节点个数*x + 剩余其他节点个数乘x即可。
收 获:让我意识到了,不但要学新算法。每天晚上还要刷题保持思路,手感。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const ll INF = 1e18;
const int maxn = 1e5+5;
int n;
map<ll,int> mp;
ll a[maxn];
ll fab(ll x){
if(x < 0)return -x;
else return x;
}
int main() {
scanf("%d",&n);
int number = 0;
ll sum1 = 0;
for(int i=1;i<=n;i++){
ll temp;
scanf("%lld",&temp);
if(!mp[temp]){
mp[temp] ++;
a[number++] = temp;
}else{
mp[temp]++;
}
sum1 += temp;
}
for(int i=0;i<n-1;i++){
int s,t;
scanf("%d %d",&s,&t);
}
ll ans = INF;
int index;
for(int i=0;i<number;i++){
ll sum2 = (ll)n*a[i];
ll sum3 = sum1 - (ll)mp[a[i]]*(ll)a[i];
ll sum4 = sum3 + (ll)(n-mp[a[i]])*(ll)a[i];
ans = min(sum4,ans);
}
printf("%lld\n",ans);
return 0;
}