Cod sursa(job #3307311)

Utilizator EricDimiCismaru Eric-Dimitrie EricDimi Data 20 august 2025 11:14:21
Problema Subsir crescator maximal Scor 5
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.6 kb
#include <bits/stdc++.h>

using namespace std;

ifstream fin("scmax.in");
ofstream fout("scmax.out");

int next_power_2(int n) {
	return (1 << (32 - __builtin_clz(n - 1)));
}

struct Node {
	int val, pos;
	Node() {
		val = pos = 0;
	}
	Node(int v, int p) {
		val = v;
		pos = p;
	}
};

const Node NULL_NODE;

Node combine(Node left_node, Node right_node) {
	Node res;
	if (left_node.val >= right_node.val) {
		res.val = left_node.val;
		res.pos = left_node.pos;
	} else {
		res.val = right_node.val;
		res.pos = right_node.pos;
	}
	return res;
}

struct SegmentTree {	
	vector<Node> tree;
	int TREE_SIZE;
	
	SegmentTree(int n) {
		TREE_SIZE = next_power_2(n);
		tree = vector<Node> (TREE_SIZE << 1, NULL_NODE);
		for (int i = 1; i < TREE_SIZE; i++)
			tree[i].pos = tree[i + TREE_SIZE].pos = i;
	}
	
	void update(int pos, int x) {
		int i = pos;
		i += TREE_SIZE;
		Node node(pos, x);
		tree[i] = combine(tree[i], node);
		while (i > 1) {
			i >>= 1;
			tree[i] = combine(tree[i << 1], tree[i << 1 | 1]);
		}
	}
	
	Node query(int left, int right) {
		Node res = NULL_NODE;
		left += TREE_SIZE;
		right += TREE_SIZE;
		while (left <= right) {
			if (left & 1)
				res = combine(res, tree[left++]);
			if (!(right & 1))
				res = combine(res, tree[right--]);
			left >>= 1;
			right >>= 1;
		}
		return res ;
	}
};

int main() {
	int n;
	fin >> n;
	
	vector<int> a(n), f(n), tmp(n), prev(n);
	for (int i = 0; i < n; i++) {
		fin >> a[i];
		tmp[i] = a[i];
	}
	
	// f[i] = lungimea maxima a unui subsir strict crescator care 
	// are ultimul element a[i] (se termina pe pozitia i)
	// f[i] = 1 + max{f[j] | j < i, a[j] < a[i]}
	// prev[i] = j, pozitia pentru care se realizeaza maximul anterior
	// prev[i] = 0, daca nu exista o alta valoare precedenta
	
	sort(tmp.begin(), tmp.end());
	tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());
	
	auto idx = [&](int val) {
		return lower_bound(tmp.begin(), tmp.end(), val) - tmp.begin();
	};
	
	for (int i = 0; i < n; i++)
		a[i] = 1 + idx(a[i]);
		
	SegmentTree st(n + 1);
	
	for (int i = 0; i < n; i++) {
		Node qry = st.query(0, a[i] - 1);
		f[i] = 1 + qry.val;
		prev[i] = qry.pos;
		st.update(a[i], f[i]);
	}
	
	int best = 0, max_len = *(max_element(f.begin(), f.end()));
	fout << max_len << "\n";
	for (int i = 0; i < n; i++)
		if (f[best] < f[i])
			best = i;
			
	vector<int> lis;
	while (best != 0) {
		lis.push_back(tmp[a[best] - 1]);
		best = prev[best];
	}
	
	for (int i = max_len - 1; i >= 0; i--)
		fout << lis[i] << " ";
	fout << "\n";
	
	fin.close();
	fout.close();	
	return 0;
}