BOJ 4002, APIO 2012 ๋์๋ฐฐ์น(Dispatching)
ํ์ด
๋ฌธ์ ํด์
๋ฒ์ญ์ด ์๋นํ ๋ํดํ๊ฒ ์์ฑ๋์ด ์๋ค. ์์ ์ ์ ๋ฆฌํ์๋ฉด
- ๋ฃจํธ ์๋ ํธ๋ฆฌ๊ฐ ์ฃผ์ด์ง๋ค.
- ๊ฐ ๋ ธ๋์๋ $L_i, C_i$ ๊ฐ์ด ์ฃผ์ด์ง๋ค.
- ํธ๋ฆฌ์ ์ด๋ค ๋ ธ๋ ํ๋ (๋งค๋์ ) ๋ฅผ ๊ณ ๋ฅธ๋ค.
- ๊ทธ ํธ๋ฆฌ๋ฅผ ๋ฃจํธ๋ก ํ๋ ์๋ธํธ๋ฆฌ์์ ๋ช ๊ฐ์ ๋ ธ๋(๋์)๋ฅผ ๊ณ ๋ฅธ๋ค. ๋งค๋์ ๋ฅผ ๋์๋ก ์ผ์ ์ ์๋ค.
- ์ด๋, ๊ณ ๋ฅธ ๋์ (๋งค๋์ ๋ฅผ ํฌํจํ์ง ์๋๋ค) ์ $C_i$ ๊ฐ์ ํฉ์ด $M$์ ๋์ด์๋ ์ ๋๋ค.
- ๋์ ์ ์ ๋, (๋งค๋์ ์ $L$ ๊ฐ) * (๊ณ ๋ฅธ ๋์์ ์) ๋ก ์ ์๋๋ค.
- ์ ์๋ฅผ ์ต๋ํํ๋ผ.
Algorithm
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฝ๊ฐ Naiveํ ์๋ฃจ์ ์ ์๊ฐํด ๋ณด์. ๊ฐ ๋ ธ๋๋ง๋ค, ๋ด๊ฐ ๋งค๋์ ์ผ ๋ ๊ณ ๋ฅด๋ ์ต์ ์ ๋์ ์กฐํฉ ์ ๊ฐ์ง๊ณ ์๋๋ค๊ณ ๊ฐ์ ํ์. ๋ด๊ฐ ๋งค๋์ ์ผ ๋๋ ๋์ ์๋ธํธ๋ฆฌ์์ ๋์๋ค์ ๊ณจ๋ผ์ผ ํ๊ณ , ์ด๋ ๊ฐ ๋์๋ ๋ชจ๋ ๋๊ฐ์ด ์ทจ๊ธ๋๋ฏ๋ก ๋ฌด์กฐ๊ฑด ์๊ธ $C_i$ ๊ฐ ๋ฎ์ ๊ฐ์ผ ๋์๋ฅผ ๋ง์ด ๋ฐฐ์นํ ์๋ก ์ด๋์ด๋ค. ์ด ๋ฐฐ์น๋ฅผ ๋ฆฌํ ๋ ธ๋๋ถํฐ ๊ฐฑ์ ํ๋ค๊ณ ์๊ฐํ์. ์ด๋, ๋์ $x$์ ๋ํ ์ต์ ๋์์กฐํฉ์ $S_x$ ๋ผ๋ ์งํฉ์ผ๋ก ์ ์ํ์.
๊ด์ฐฐ $x$์ ancestor node $p$์ ๋ํด, $S_x$์ ํฌํจ๋์ง ์๋ ๋ ธ๋๋ $S_p$์ ํฌํจ๋์ง ์๋๋ค.
์ฆ๋ช $S_p$๋ฅผ ์ด๋ป๊ฒ ๋ง๋ค์ง ์๊ฐํด ๋ณด์. ๋จผ์ , $S_p$๋ฅผ ๋ง๋๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ ์ค ํ๋๋, ์๊ธฐ ์์ ๋ ธ๋ $v_1, \dots v_k$ ์ ๋ํด $S_{v_i}$ ๋ค์ ๋ชจ๋ ํฉ์งํฉํ ๋ค์, ๋น์ฉ์ด $M$๋ณด๋ค ์๊ฑฐ๋ ๊ฐ์์ง ๋๊น์ง ๋น์ผ ๋์๋ฅผ ๊ณ์ ์๋ฅด๋ ๋ฐฉ๋ฒ์ด ์๋ค. ์ด ๋ฐฉ๋ฒ์ด ์ฌ๋ฐ๋ฅธ $S_p$๋ฅผ ๋ณด์ฅํจ์ ์ด๋ ต์ง ์๊ฒ ๋ณด์ฌ์ง๋ค.
์ด ๊ด์ฐฐ๋ก๋ถํฐ ์ป์ด์ง๋ ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐ ๋ณต์ก๋๋ฅผ ์๊ฐํด ๋ณด์. ๊ฐ ๋ ธ๋๋ง๋ค, ์๊ธฐ ์์ ๋ ธ๋์ ๋ชจ๋ set์ ํฉ์ณ์ผ ํ๊ณ , ํ์ํ๋ค๋ฉด ๋์๋ค์ ํด๊ณ ํด์ผ ํ๋ค. ์ด๋ $S_x$๋ฅผ set์ด๋ priority queue์ ๊ฐ์ ์๋ฃ๊ตฌ์กฐ๋ฅผ ์ด์ฉํ์ฌ ๊ด๋ฆฌํ๋ค๋ฉด, ์ต๋ $n$๋ฒ ํฉ์งํฉ ์ฐ์ฐ์ ํด์ผ ํ๋ฉฐ, ๊ฐ ์งํฉ์ ํฌ๊ธฐ๊ฐ ์ต๋ $n$๊น์ง ๊ฐ ์ ์๊ณ , ์์ ํ๋๋ฅผ ์์ง์ด๋ ๋ฐ $O(\log n)$ ์๊ฐ์ด ๋ค ๊ฒ์ด๋ฏ๋ก $O(n^2 \log n)$ ์๊ฐ์ด ์์๋๋ค.
Merge sort tree๋ฅผ ๋ง๋๋ ๋์ ๋น์ทํ๊ฒ, set์ ์ฐ์ง ์๊ณ vector ๊ฐ์๊ฒ์ ์ ๋ ฌํด์ ๊ฐ์ง๊ณ ์์ผ๋ฉด์ mergeํ๋ฉด $O(n^2)$ ์๊ฐ์๋ ์ด๋ป๊ฒ ๊ฐ๋ฅํ ๊ฒ ๊ฐ๊ธฐ๋ ํ๋ค. ์ด ๋ฐฉ๋ฒ์ ๊ตฌํํด ๋ณด์ง ์์์ ๋ณต์ก๋์๋ ์์ ์ด ์๋ค.
Small-to-Large Technique
์์ฃผ ์์ ๋ถ๋ถ์ ๋ฐ๊ฟ์ผ๋ก์จ ์๊ฐ ๋ณต์ก๋๋ฅผ ์ค์ด๋ ํ ํฌ๋์ธ๋ฐ, ๊ต์ฅํ ์๋ฆ๋ต๋ค. ์์ง๋, ์ ์๊ณ ๋ฆฌ์ฆ์ ๊ทธ๋๋ก ์ํํ๋, set์ ํฉ์น ๋ ํญ์ ์์ ์งํฉ์ ์๋ ์์๋ค์ ํฐ ์งํฉ์ผ๋ก ์ฎ๊ธฐ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ง ํฉ์น๋ ๊ฒ์ด๋ค. ์ฌ๋ฌ ๊ฐ๋ฅผ ํฉ์น ๋๋ ๊ฐ์ฅ ํฐ ๊ฒ์ ๊ธฐ์ค์ผ๋ก ๋๋จธ์ง๋ฅผ ๊ฑฐ๊ธฐ์ ์ง์ด๋ฃ๊ธฐ๋ก ํ์.
์ด ๋ฐฉ๋ฒ์ด ๋ณต์ก๋๋ฅผ ์ค์ฌ ์ค์ ์ฆ๋ช ํ์.
์ฆ๋ช
๊ฐ ๋์ $x$๋ง๋ค, $x$๊ฐ ํฌํจ๋ ์งํฉ์ด ์์ ๊ฒ์ด๋ค. (์งํฉ์์ ํ ๋ฒ ๋น ์ง ๋์๋ ์ฌ๋ผ์ง๋ ๊ฒ์ด๋ฏ๋ก, ๊ทธ๊ฑธ ์๋ก์ด ์งํฉ์ฒ๋ผ ์๊ฐํ์) ์ ์๊ณ ๋ฆฌ์ฆ์ ์ํ ๊ณผ์ ์ ์์ผ๋ก ๊ทธ๋ ค ๋ณด๋ฉด, ๊ฐ ์์๋ง๋ค ๋ชจ๋ ์งํฉ๋ค์ ํตํ์ด ํ ๋ฒ๋ง ์์ผ๋ฉด ๋๋ค (๋ค ๊ณ์ฐํ ๋ค์ ์์ ๋
ธ๋์ $S_v$ ๋ค์ ๋ชจ๋ ์ง์๋ฒ๋ ค๋ ๋๋ฏ๋ก).
๋ฐ๋ผ์, $x$๊ฐ ํฌํจ๋ ์งํฉ $T(x)$ ๋ฅผ ํญ์ identify ํ ์ ์๋ค.
์ด๋, $T(x)$์ ํฌ๊ธฐ๋ฅผ ๋ฐํํ๋ ํจ์ $f(x)$๋ฅผ ์๊ฐํ์. $f(x)$๋, ์ฆ, ์ง๊ธ ์ด ์๊ฐ x๊ฐ ํฌํจ๋์ด ์๋ ์งํฉ์ ํฌ๊ธฐ ๋ผ๊ณ ์ ์ํ๋ค. ์์ $x$๊ฐ ์ด๋ค ์งํฉ $A$์์ ๋ค๋ฅธ ์งํฉ $B$๋ก ์ด๋ํ๋ค๋ฉด, ์ฆ $T(x)$๊ฐ $A$์์ $B$๋ก ๋ณ๊ฒฝ๋๋ค๋ฉด ์ด๋ค ์ผ์ด ์ผ์ด๋๋์ง ์๊ฐํด ๋ณด์. ๋ง์ฝ $A$๊ฐ $B$๋ณด๋ค ์์๋ค๋ฉด, $x$ ํ๋๋ง ์ฎ๊ธฐ๋๊ฒ ์๋๋ผ $A$๋ฅผ ํต์งธ๋ก ๋ค์ด๋ค๊ฐ $B$๋ก ์ฎ๊ธธ ๋๋ง $x$๊ฐ ์์ง์ด๋ฏ๋ก $T(x)$๋ $\abs{A}$์์ $\abs{A} + \abs{B}$๋ก ๋ฐ๋๊ฒ ๋์ด, ์ ์ด๋ 2๋ฐฐ ์ด์ ๋์ด๋๋ค. ๋ฐ๋ฉด ๋ง์ฝ $A$๊ฐ $B$๋ณด๋ค ์ปธ๋ค๋ฉด, $A$์ $B$๋ฅผ ํฉ์น๋๋ผ๋ $x$๋ ์์ง์ด์ง ์๊ณ $B$์ ์์๋ ์์๋ค์ด ์ด์ชฝ์ผ๋ก ์์ง์ผ ๊ฒ์ด๋ค. ์ฆ, $x$๋ฅผ relocate ํ๋ ์ฐ์ฐ์ด ์ผ์ด๋๋ค๋ฉด ๋ฐ๋์ $f(x)$๊ฐ 2๋ฐฐ ์ด์ ์ฆ๊ฐํ๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
์ด๋, ๋น์ฐํ์ง๋ง ์ค์ํ ์ฌ์ค์ ๋น์ฐํ $f(x)$๋ $n$์ ๋์ ์ ์๋ค๋ ์ ์ด๋ค. ๋ฐ๋ผ์, ์ด ์ฌ์ค๋ค์ ์ข ํฉํ๋ฉด, $x$๋ ์ต๋ $O(\log n)$ ๋ฒ๋ง ์ด๋ํ ์ ์๋ค๋ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค.
๋ฐ๋ผ์, ์ด ํ ํฌ๋์ ์ ์ฉํ๋ฉด, ๋ชจ๋ ์์๋ ์ต๋ $O(\log n)$ ๋ฒ ์์ง์ด๊ณ , ์์ง์ผ๋๋ง๋ค $O(\log n)$ ์๊ฐ์ด ์๋ชจ๋๋ฏ๋ก ์ ์ฒด ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐ ๋ณต์ก๋๊ฐ $O(n \log^2 n)$์ผ๋ก ํฌ๊ฒ ์ค์ด๋ ๋ค. ์ด ํ ํฌ๋์ smaller-to-larger ๊ฐ์ ์ด๋ฆ์ผ๋ก ๋ถ๋ฅด๊ธฐ๋ ํ๋๋ฐ, ์์ ์ ์ฝ๊ฐ DSU์์ union by size ํ ๋ ๋ณต์ก๋ ์ฆ๋ช ํ ๋์ ๊ฐ๋ค.
๊ตฌํ๋ ๊ต์ฅํ ์ฝ๊ฒ ํ ์ ์๋ค.
์ฝ๋
#include <bits/stdc++.h>
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#define ll long long
#define int ll
#define eps 1e-7
#define all(x) ((x).begin()),((x).end())
#define usecppio ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
using pii = pair<int, int>;
struct PQueue
{
priority_queue <int> pq;
int total = 0;
void push(int x)
{
pq.push(x);
total += x;
}
int peek() {return pq.top();}
int pop()
{
int x = pq.top();
total -= x;
pq.pop();
return x;
}
int size() {return (int)(pq.size());}
bool empty() {return pq.empty();}
};
void merge(PQueue &dest, PQueue &src)
{
if (dest.size() < src.size())
swap(dest, src);
while (!src.empty())
dest.push(src.pop());
}
int n, m, ans;
vector <int> T[101010];
vector <PQueue> PQS(101010);
int lead[101010], cost[101010];
void dfs(int r, int p)
{
PQS[r].push(cost[r]);
for (int c : T[r])
if (c != p)
dfs(c, r);
for (int c : T[r])
if (c != p)
merge(PQS[r], PQS[c]);
while (PQS[r].total > m)
PQS[r].pop();
ans = max(ans, lead[r] * PQS[r].size());
}
int32_t main()
{
usecppio
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
int b, c, l; cin >> b >> c >> l;
T[b].push_back(i);
T[i].push_back(b);
lead[i] = l;
cost[i] = c;
}
cost[0] = INT_MAX;
dfs(0, -1);
cout << ans << '\n';
}