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.
Forget trees for a second. A tree exists exactly when the graph of all allowed edges is connected, because any connected graph contains a spanning tree.
For labels , edge is allowed iff . So if you write by increasing label , edges are exactly increasing pairs with .
Think about a split between labels and . There is no edge crossing this split iff every left position is after every right position, i.e. .
If such a dead split exists, no tree can connect both sides. The graph is toast. If no such split exists, every consecutive label block in the component-building process has some increasing pair to the next side, so components merge until one remains.
So precompute prefix minimum of positions and suffix maximum of positions. Answer No iff there exists with ; otherwise answer Yes. Tiny condition, big payoff. Classic 1400 disguised as a tree problem wearing a fake mustache.
Let be the position of value in the permutation.
The condition for an edge is:
So define an auxiliary graph with vertices , where we put an edge between and exactly when that edge is legal.
Now the whole tree part is basically bait. A tree satisfying the rule exists iff is connected, because:
So we only need to test whether this graph is connected.
Rewriting the graph
Look at labels in increasing order: .
Let
For , edge exists iff
So edges are exactly increasing pairs in the array .
When is the graph disconnected?
Suppose we split labels after :
An edge across this split would need some and with:
So there is no edge across the split iff every value on the left is larger than every value on the right:
If this happens, the graph is disconnected immediately. No spanning tree. No magic. The tree is dead.
Why checking only these prefix/suffix splits is enough
A disconnected graph has at least two connected components. Take the component containing label , and let be the largest label in that component.
If , then no vertex can have an edge to any vertex in this component. In particular, since through can be considered as a separated left block at the first place where connectivity cannot continue, there must be a split where every left position is after every right position. In terms of , that is exactly:
Another way to see it: if for every there exists some crossing increasing pair, then every prefix has at least one legal edge going to the suffix. That prevents the labels from being separated into multiple connected chunks, so all vertices merge into one connected graph.
So the whole problem reduces to finding whether such a “reverse wall” exists.
Algorithm
For each test case:
then answer No.
Otherwise answer Yes.
Complexity
Each test case is .
Across all test cases, this is , which easily fits. The constraints are not the boss fight here; the trick is realizing the “tree” is just connectivity in a very specific graph.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> pos(n + 1);
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
pos[x] = i;
}
vector<int> prefMin(n + 2, n + 1), suffMax(n + 2, 0);
for (int i = 1; i <= n; i++) {
prefMin[i] = min(prefMin[i - 1], pos[i]);
}
for (int i = n; i >= 1; i--) {
suffMax[i] = max(suffMax[i + 1], pos[i]);
}
bool ok = true;
for (int k = 1; k < n; k++) {
if (prefMin[k] > suffMax[k + 1]) {
ok = false;
break;
}
}
cout << (ok ? "Yes" : "No") << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> pos(n + 1);
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
pos[x] = i;
}
vector<int> prefMin(n + 2, n + 1), suffMax(n + 2, 0);
for (int i = 1; i <= n; i++) {
prefMin[i] = min(prefMin[i - 1], pos[i]);
}
for (int i = n; i >= 1; i--) {
suffMax[i] = max(suffMax[i + 1], pos[i]);
}
bool ok = true;
for (int k = 1; k < n; k++) {
if (prefMin[k] > suffMax[k + 1]) {
ok = false;
break;
}
}
cout << (ok ? "Yes" : "No") << '\n';
}
return 0;
}