// 解法:各点 (i, P_i) の層 = 「i で終わる最長増加部分列の長さ」 // パーシェンスソーティングで各 i の LIS 長 L_i を O(log N) で求める。 // 各層 k について、x の最小値 = 最小の i, y の最小値 = 最小の P_i を集計して出力。 #include using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; if (!(cin >> N)) return 0; vector P(N); for (int i = 0; i < N; ++i) cin >> P[i]; vector tails; // tails[len-1] = 長さ len の増加列の最小 possible 終端値 vector L(N); // 各 i の LIS 長(厳密増加) tails.reserve(N); for (int i = 0; i < N; ++i) { int a = P[i]; // 厳密増加 LIS: lower_bound (>= a) の位置に置く int pos = int(lower_bound(tails.begin(), tails.end(), a) - tails.begin()); if (pos == (int)tails.size()) tails.push_back(a); else tails[pos] = a; L[i] = pos + 1; // 層番号 = LIS 長 } int K = (int)tails.size(); // 総ラウンド数 = 総層数 const int INF = 1e9; vector minX(K + 1, INF), minY(K + 1, INF); // 1-indexed 層 for (int i = 0; i < N; ++i) { int k = L[i]; minX[k] = min(minX[k], i + 1); // x = index i+1 minY[k] = min(minY[k], P[i]); // y = P_i } for (int k = 1; k <= K; ++k) { cout << minX[k] << ' ' << minY[k] << '\n'; } return 0; }