Skip to content

Commit 74430a7

Browse files
committed
Dodano rozwiązanie zadania 'Przelewy' z XXV OI
1 parent b1648b5 commit 74430a7

File tree

1 file changed

+153
-0
lines changed
  • rozwiazania/xxv/etap2/probne/prz

1 file changed

+153
-0
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Rozwiązanie zadania 'Przelewy' z II etapu XXV OI.
2+
// Autor: Paweł Putra
3+
// Złożoność czasowa: O(n * log(n)).
4+
// Złożoność pamięciowa: O(n).
5+
// Punkty: 100 (upsolve).
6+
7+
#include <bits/stdc++.h>
8+
#define sz(x) (int)(x).size()
9+
#define dbg(x) #x << " = " << x << " "
10+
using namespace std;
11+
using ll = long long;
12+
constexpr int MAXN = 1'000'005, BASE = 1'000'000'000;
13+
ll brak[MAXN], up[MAXN], down[MAXN], par[MAXN];
14+
int deg[MAXN];
15+
vector<int> g[MAXN];
16+
17+
// Wynik może wyjść nawet 10^24.
18+
// Na konkursie nie było pythona ani __int128_t.
19+
struct BigInt {
20+
vector<int> d;
21+
BigInt(ll x) {
22+
if (x >= BASE) d = {x / BASE, x % BASE};
23+
else d = {x};
24+
}
25+
26+
BigInt(vector<int> &x) : d(x) {}
27+
BigInt operator+(const BigInt &y) {
28+
vector<int> nowy;
29+
int nadmiar = 0;
30+
31+
int i = d.size() - 1;
32+
int j = y.d.size() - 1;
33+
while (i >= 0 || j >= 0) {
34+
int a = (i >= 0 ? d[i] : 0);
35+
int b = (j >= 0 ? y.d[j] : 0);
36+
int sum = a + b + nadmiar;
37+
if (sum >= BASE) nadmiar = 1, sum -= BASE;
38+
else nadmiar = 0;
39+
nowy.push_back(sum);
40+
i--;
41+
j--;
42+
}
43+
if (nadmiar) nowy.push_back(1);
44+
45+
reverse(nowy.begin(), nowy.end());
46+
return BigInt(nowy);
47+
}
48+
49+
// Mnożenie w log_2(x), bo jestem leniwy.
50+
BigInt operator*(ll x) {
51+
if (d.size() == 1 && d[0] == 0) return BigInt(0LL);
52+
BigInt pot = BigInt(d);
53+
BigInt res(0LL);
54+
while (x > 0) {
55+
if (x & 1) res = res + pot;
56+
pot = pot + pot;
57+
x /= 2;
58+
}
59+
60+
return res;
61+
}
62+
63+
friend ostream& operator<<(ostream &out, const BigInt &x) {
64+
out << x.d[0];
65+
for (int i = 1; i < x.d.size(); i++) {
66+
out << setfill('0') << setw(9) << x.d[i];
67+
}
68+
return out;
69+
}
70+
} wynik(0LL);
71+
72+
int32_t main() {
73+
ios_base::sync_with_stdio(0);
74+
int n;
75+
cin >> n;
76+
for (int i = 1; i <= n; i++) {
77+
cin >> brak[i];
78+
}
79+
80+
for (int i = 1; i <= n; i++) {
81+
int x;
82+
cin >> x;
83+
brak[i] = x - brak[i];
84+
}
85+
86+
for (int i = 1; i < n; i++) {
87+
int a, b;
88+
cin >> a >> b;
89+
deg[a]++;
90+
deg[b]++;
91+
par[a] += b;
92+
par[b] += a;
93+
g[a].push_back(b);
94+
g[b].push_back(a);
95+
}
96+
97+
queue<int> q;
98+
for (int i = 1; i <= n; i++) {
99+
if (deg[i] == 1) q.push(i);
100+
}
101+
102+
// Nie liczę dfsem, bo mi pamięci nie starczało, trik na obgryzanie liści.
103+
while (!q.empty()) {
104+
int v = q.front();
105+
q.pop();
106+
up[v]++;
107+
108+
int p = par[v];
109+
110+
// Spełniam żądania synów.
111+
brak[v] += 1LL * down[v] * sz(g[v]);
112+
wynik = wynik + BigInt(down[v]);
113+
// Niektórym mogłem oddać za dużo, to mi oddają.
114+
for (auto s : g[v]) {
115+
brak[s] -= down[v];
116+
if (s != p) {
117+
wynik = wynik + BigInt(-brak[s]) * up[s];
118+
brak[v] += brak[s];
119+
}
120+
}
121+
122+
// W korzeniu nie mam już opcji zabrać/oddać ojcu.
123+
if (deg[v] == 0 && brak[v] != 0) {
124+
cout << "NIE\n";
125+
exit(0);
126+
}
127+
128+
if (brak[v] < 0) {
129+
ll nadmiar = -brak[v];
130+
// Wysyłam nadmiar do ojca.
131+
wynik = wynik + BigInt(nadmiar) * up[v];
132+
brak[p] -= nadmiar;
133+
brak[v] = 0;
134+
} else {
135+
// Żądam od ojca, żeby wysłał mi tyle ile potrzebuję.
136+
down[p] = max(down[p], brak[v]);
137+
}
138+
139+
deg[v]--;
140+
par[p] -= v;
141+
deg[p]--;
142+
up[p] += up[v];
143+
if (deg[p] == 1) {
144+
q.push(p);
145+
}
146+
147+
}
148+
149+
150+
cout << "TAK\n";
151+
cout << wynik << "\n";
152+
}
153+

0 commit comments

Comments
 (0)