Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Don’t try to guess the final water heights directly. Look at the water one horizontal layer at a time: layer contributes to every vessel with .
For a fixed layer , an edge with is dangerous: if one side has water reaching layer , the other side must also have it, because the water is above that connection.
Fix the empty vessel . At layer , every vessel connected to using only edges with is forced to be empty at that layer. Otherwise the empty vessel would also need water at layer — nonsense.
The cute part: every vessel not in that connected component can safely be filled at layer . So the best contribution of layer is
where is the component of using edges with .
Process layers only when something changes. Sort edges by height. For a fixed root , maintain a DSU of edges with height . Before adding edges of height , the answer gains
Then union all edges of height . Repeat this independently for every . Since , is totally fine.
The condition is annoying if we stare at full heights . So don’t. Slice the water horizontally.
For an integer layer , vessel contains this layer iff
Since
we can maximize the contribution of every layer separately — as long as the chosen sets are nested. Luckily, they will be.
Consider an edge between two neighboring vessels with partition height .
If , then layer lies above this partition. Therefore, if one side has water at layer , the other side must also have water at layer . In the formal condition: one height is at least , so differing heights would be illegal.
So at layer , all vertices connected by edges satisfying
must either all contain this layer or all not contain it.
Now fix the vessel that must remain empty, i.e. . It never contains any layer. Therefore, every vessel in the connected component of using only edges with also cannot contain layer .
All other vessels can contain layer .
Thus the maximum possible contribution of layer is
where is the component of in the graph containing exactly edges with .
For every layer , fill exactly the vessels outside 's component in the graph of edges with .
As increases, more edges become active, so 's component only grows. Therefore the set of filled vessels only shrinks. These layer choices are nested, so they define valid integer heights .
Also, if two neighboring vessels get different final heights, let the larger height be . At layer , one side is filled and the other is not, so their edge could not have been active. Hence
which is exactly the condition needed for a good array. No black magic, just layers doing the heavy lifting.
The graph changes only when passes some height .
Sort all cycle edges by height. For a fixed empty vessel , maintain a DSU containing all edges with height at most prev. These are exactly the edges with
for every layer in the next interval.
Suppose the next distinct edge height is . For all layers
the active edges are unchanged. There are such layers, and each contributes
So we add
Then union all edges of height , set , and continue.
After the largest height, all cycle edges are active, so every vessel is connected to and the contribution becomes forever.
We repeat this process for each possible empty vessel .
For each root, we process edges with DSU operations. Therefore one test case costs
and since the statement guarantees
this easily fits. Memory usage is
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct DSU {
vector<int> p, sz;
DSU(int n = 0) {
init(n);
}
void init(int n) {
p.resize(n);
sz.assign(n, 1);
iota(p.begin(), p.end(), 0);
}
int find(int x) {
while (x != p[x]) {
p[x] = p[p[x]];
x = p[x];
}
return x;
}
void unite(int a, int b) {
a = find(a);
b = find(b);
if (a == b) return;
if (sz[a] < sz[b]) swap(a, b);
p[b] = a;
sz[a] += sz[b];
}
int size(int x) {
return sz[find(x)];
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> h(n);
for (int i = 0; i < n; i++) cin >> h[i];
vector<tuple<ll, int, int>> edges;
edges.reserve(n);
for (int i = 0; i < n; i++) {
int u = i;
int v = (i + 1) % n;
edges.emplace_back(h[i], u, v);
}
sort(edges.begin(), edges.end());
vector<ll> ans(n, 0);
for (int root = 0; root < n; root++) {
DSU dsu(n);
ll prev = 0;
ll cur_ans = 0;
int ptr = 0;
while (ptr < n) {
ll x = get<0>(edges[ptr]);
cur_ans += (x - prev) * (ll)(n - dsu.size(root));
while (ptr < n && get<0>(edges[ptr]) == x) {
auto [height, u, v] = edges[ptr];
dsu.unite(u, v);
ptr++;
}
prev = x;
}
ans[root] = cur_ans;
}
for (int i = 0; i < n; i++) {
cout << ans[i] << ' ';
}
cout << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct DSU {
vector<int> p, sz;
DSU(int n = 0) {
init(n);
}
void init(int n) {
p.resize(n);
sz.assign(n, 1);
iota(p.begin(), p.end(), 0);
}
int find(int x) {
while (x != p[x]) {
p[x] = p[p[x]];
x = p[x];
}
return x;
}
void unite(int a, int b) {
a = find(a);
b = find(b);
if (a == b) return;
if (sz[a] < sz[b]) swap(a, b);
p[b] = a;
sz[a] += sz[b];
}
int size(int x) {
return sz[find(x)];
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> h(n);
for (int i = 0; i < n; i++) cin >> h[i];
vector<tuple<ll, int, int>> edges;
edges.reserve(n);
for (int i = 0; i < n; i++) {
int u = i;
int v = (i + 1) % n;
edges.emplace_back(h[i], u, v);
}
sort(edges.begin(), edges.end());
vector<ll> ans(n, 0);
for (int root = 0; root < n; root++) {
DSU dsu(n);
ll prev = 0;
ll cur_ans = 0;
int ptr = 0;
while (ptr < n) {
ll x = get<0>(edges[ptr]);
cur_ans += (x - prev) * (ll)(n - dsu.size(root));
while (ptr < n && get<0>(edges[ptr]) == x) {
auto [height, u, v] = edges[ptr];
dsu.unite(u, v);
ptr++;
}
prev = x;
}
ans[root] = cur_ans;
}
for (int i = 0; i < n; i++) {
cout << ans[i] << ' ';
}
cout << '\n';
}
return 0;
}