Cod sursa(job #2035477)

Utilizator robuvedVictor Robu robuved Data 9 octombrie 2017 14:57:15
Problema Arbori de intervale Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 5.77 kb
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;

struct Seq
{
	int s, e;
	long long sum;
	int prev_seq;
	int neg_sum_between;
};

bool CompareSmaller(int a, int b)
{
	return a < b;
}
bool CompareGreater(int a, int b)
{
	return a > b;
}
class SegTree
{
	vector<int> v;
	vector<int> tree;
	bool(*Comparator)(int, int);
	void Build(int node, int left, int right)
	{
		if (left == right)
		{
			tree[node] = left;
			return;
		}
		int mid = (left + right) / 2;
		int leftc = 2 * node + 1;
		int rightc = leftc + 1;

		Build(leftc, left, mid);
		Build(rightc, mid + 1, right);

		if (Comparator(v[tree[leftc]], v[tree[rightc]]))
			tree[node] = tree[leftc];
		else
			tree[node] = tree[rightc];
	}
	int QueryUtil (int node, int left, int right, int x, int y)
	{
		if (y < left || x > right)
		{
			return -1;
		}
		if (left >= x && right <= y)
			return tree[node];
		int mid = (left + right) / 2;
		int leftc = 2 * node + 1;
		int rightc = leftc + 1;

		int first = QueryUtil(leftc, left, mid, x, y);
		int second = QueryUtil(rightc, mid + 1, right, x, y);

		if (first < 0)
			return second;
		else if (second < 0)
			return first;
		if (Comparator(v[first], v[second]))
			return first;
		else
			return second;
	}

public:
	SegTree(vector<int> V, bool(*c)(int, int)) : Comparator(c), v(V), tree(4 * V.size(), 0) { Build(0, 0, V.size() - 1); }
	int Query(int x, int y)
	{
		return QueryUtil(0, 0, v.size() - 1, x, y);
	}
};


long long max_sum;
int max_swap_i, max_swap_j;

void UpdateMaxOneSeq(vector<int>& v, SegTree& minTree, SegTree& maxTree, Seq& seq)
{
	int min_i_in_seq = minTree.Query(seq.s, seq.e);

	if (seq.sum - v[min_i_in_seq] > max_sum)
	{
		max_sum = seq.sum - v[min_i_in_seq];
		max_swap_i = min_i_in_seq;
		max_swap_j = seq.s;
	}

	int max_i_out_seq = -1;
	if (0 <= seq.s - 1)
	{
		int max_i_left_seq = maxTree.Query(0, seq.s - 1);
		max_i_out_seq = max_i_left_seq;
	}
	if (seq.e + 1 <= v.size() - 1)
	{
		int max_i_right_seq = maxTree.Query(seq.e + 1, v.size() - 1);
		if (max_i_out_seq < 0 || v[max_i_right_seq] > v[max_i_out_seq])
		{
			max_i_out_seq = max_i_right_seq;
		}
	}
	if (max_i_out_seq >= 0 && max_sum < seq.sum - v[min_i_in_seq] + v[max_i_out_seq])
	{
		max_sum = seq.sum - v[min_i_in_seq] + v[max_i_out_seq];
		max_swap_i = min_i_in_seq;
		max_swap_j = max_i_out_seq;
	}

	if (max_i_out_seq >= 0 && max_sum < seq.sum + v[max_i_out_seq])
	{
		max_sum = seq.sum + v[max_i_out_seq];
		max_swap_i = max_i_out_seq;
		max_swap_j = seq.s > 0 ? seq.s - 1: seq.e + 1;
	}
}

void UpdateMaxTwoSeq(vector<int>& v, SegTree& minTree, SegTree& maxTree, Seq& seq1, Seq& seq2, int neg_sum_between)
{
	int min_i_between = minTree.Query(seq1.s + 1, seq2.e - 1);

	if (seq1.sum + seq2.sum + neg_sum_between - v[min_i_between] > max_sum)
	{
		max_sum = seq1.sum + seq2.sum + neg_sum_between - v[min_i_between];
		max_swap_i = min_i_between;
		max_swap_j = seq1.s;
	}

	int max_i_out_seq = -1;
	if (0 <= seq1.s - 1)
	{
		int max_i_left_seq = maxTree.Query(0, seq1.s - 1);
		max_i_out_seq = max_i_left_seq;
	}
	if (seq2.e + 1 <= v.size() - 1)
	{
		int max_i_right_seq = maxTree.Query(seq2.e + 1, v.size() - 1);
		if (max_i_out_seq < 0 || v[max_i_right_seq] > v[max_i_out_seq])
		{
			max_i_out_seq = max_i_right_seq;
		}
	}
	if (max_i_out_seq >= 0 && max_sum < seq1.sum + seq2.sum + neg_sum_between - v[min_i_between] + v[max_i_out_seq])
	{
		max_sum = seq1.sum + seq2.sum + neg_sum_between - v[min_i_between] + v[max_i_out_seq];
		max_swap_i = min_i_between;
		max_swap_j = max_i_out_seq;
	}
}

int main()
{
	int n;
	cin >> n;
	vector<int> v(n, 0);
	for (int i = 0; i < n; i++)
	{
		cin >> v[i];
	}
	vector<Seq> seqs;
	long long sc = 0;
	int ic = 0;
	int prev_seq = -1;
	int last_pos_i = -1;
	int prev_longest_seq_i = -1;
	int current_max_sum_seq_i = -1;
	long long cur_neg_seq_sum = 0;
	long long prev_neg_sum_between = 0;
	long long neg_sum_between = 0;

	for (int i = 0; i < n; i++)
	{
		if (i > 0 && v[i] < 0 && v[i - 1] > 0)
		{
			seqs.push_back({ ic, i - 1, sc, -1, -1 });
			if (current_max_sum_seq_i < 0 || sc > seqs[current_max_sum_seq_i].sum)
				current_max_sum_seq_i = seqs.size() - 1;
		}

		if (v[i] < 0)
			cur_neg_seq_sum += v[i];
		else
			cur_neg_seq_sum = 0;
		if (sc + v[i] < 0)
		{
			ic = i + 1;
			if (current_max_sum_seq_i >= 0)
			{
				seqs[current_max_sum_seq_i].prev_seq = prev_longest_seq_i;
				seqs[current_max_sum_seq_i].neg_sum_between = neg_sum_between;

				prev_longest_seq_i = seqs.size() - 1;
				current_max_sum_seq_i = -1;
			}
			neg_sum_between = cur_neg_seq_sum;
			sc = 0;
		}
		else
		{
			sc += v[i];
		}
	}
	if (v[v.size() - 1] > 0)
	{
		seqs.push_back({ ic, (int)v.size() - 1, sc, -1, -1 });
		if (current_max_sum_seq_i < 0 || sc > seqs[current_max_sum_seq_i].sum)
			current_max_sum_seq_i = seqs.size() - 1;
		seqs[current_max_sum_seq_i].prev_seq = prev_longest_seq_i;
		seqs[current_max_sum_seq_i].neg_sum_between = neg_sum_between;
		prev_longest_seq_i = seqs.size() - 1;
		current_max_sum_seq_i = -1;
	}
	SegTree treeMin(v, CompareSmaller), treeMax(v, CompareGreater);
	if (seqs.empty())
	{
		int poz = max_element(v.begin(), v.end()) - v.begin();
		cout << v[poz] << endl << "1 " << poz << endl;
		return 0;
	}
	if (seqs[0].s == 0 && seqs[0].e == v.size() - 1)
	{
		std::cout << seqs[0].sum << endl << "1 2" << endl;
		return 0;
	}
	for (int i = 0; i < seqs.size(); i++)
	{
		UpdateMaxOneSeq(v, treeMin, treeMax, seqs[i]);
		if (seqs[i].prev_seq >= 0)
		{
			UpdateMaxTwoSeq(v, treeMin, treeMax, seqs[seqs[i].prev_seq], seqs[i], seqs[i].neg_sum_between);
		}
	}
	cout << max_sum << endl;
	cout << max_swap_i + 1 << ' ' << max_swap_j + 1<< endl;
	return 0;
}