안녕하세요. 오늘은 분필도둑이 될거예요.
https://www.acmicpc.net/problem/25428
최대한 많이 가져갈수록 이득입니다.
그래서 특정개수 x에 대해서 그 이상의 분필을 가진 교실들만 모아서 처리를 합시다.
그런데 이를 매번 다 하면 시간초과가 나므로 x가 최댓값부터 쭉 내려오면서 조금씩 크기를 키워나가면 됩니다.
이때 정답은 x*(그때의 집합들중 크기가 최대)인 값이 됩니다.
#include <iostream>
#include <vector>
#include <algorithm>
#define ll long long
using namespace std;
ll parent[101010] = { 0 }, mx = 0;
ll find(ll x)
{
if (parent[x] < 0) return x;
return parent[x] = find(parent[x]);
}
void Union(ll x, ll y)
{
x = find(x); y = find(y);
parent[x] += parent[y];
parent[y] = x;
mx = max(mx, max(-parent[x], -parent[y]));
}
bool same(ll x, ll y)
{
return find(x) == find(y);
}
int main(void)
{
ios_base::sync_with_stdio(false); cin.tie(NULL);
ll N, i, bunpil[101010] = { 0 }, a, b, ans = 0;
vector <pair <ll, pair <ll, ll> > > v;
cin >> N;
for (i = 1; i <= N; i++) parent[i] = -1;
for (i = 1; i <= N; i++)
{
cin >> bunpil[i];
ans = max(ans, bunpil[i]); //한개만 선택하는 경우
}
for (i = 0; i < N - 1; i++)
{
cin >> a >> b;
v.push_back({ min(bunpil[a],bunpil[b]),{a,b} });
}
sort(v.begin(), v.end(), greater<>());
for (i = 0; i < N - 1; i++)
{
if (same(v[i].second.first, v[i].second.second)) continue;
Union(v[i].second.first, v[i].second.second);
ans = max(ans, v[i].first * mx);
}
cout << ans;
}
감사합니다.