Cod sursa(job #133555)

Utilizator alexandru.mosoiAlexandru Mosoi alexandru.mosoi Data 8 februarie 2008 22:17:04
Problema Eprubeta Scor Ascuns
Compilator cpp Status done
Runda Marime 4.86 kb
#include <cstdio>
#include <cassert>
#include <algorithm>

#define maxN 2048
#define INFI 0x3f3f3f3f

using namespace std;

struct skl {
	int sum;
	int right;

	void update();
};

int N, M;
int dia[maxN];
int lst[maxN][2];

skl pool[2 * maxN * maxN];
int pool_head = 0;

inline void skl::update() {
	sum = (this + 1)->sum;
	if (right != INFI) sum += pool[right].sum;
}

/*
void recursive_print(skl* lista) {
	if (lista == NULL) return;

	static int level = -1;
	++level;

	printf("%3d ", lista->sum);
	recursive_print(lista->left);

	printf("\n    ");
	for (int i = 0; i < level; ++i)
		printf("    ");
	recursive_print(lista->right);

	--level;
}

int recursive_check(skl* lista) {
	if (lista->end - lista->begin == 1)
		return lista->sum;

	assert(lista->sum == recursive_check(lista->left) +
			             recursive_check(lista->right));
	return lista->sum;
}

void print(skl* lista, const char* name) {
	printf("=============================\n");
	printf("%s:\n", name);

	recursive_print(lista);
	printf("\n");
	recursive_check(lista);

	printf("*****************************\n");
}

#define print(lista) print(lista, #lista)
*/

int query_count = 0;

int create(int* line, int begin, int end, int limit) {
	++query_count;

	if (begin >= limit) return INFI;
	const int node = pool_head++;

	if (end - begin != 1) {
		const int mid = (begin + end) / 2;

		create(line, begin, mid, limit);                   // left
		pool[node].right = create(line, mid, end, limit);  // right
		pool[node].update();
	} else {
		pool[node].right = INFI;
		pool[node].sum = line[begin];
	}

	return node;
}

int query(int lista, int count) {
	int sum = 0;
	int begin = 0;
	int end = N;

	while (lista != INFI) {
		++query_count;

		const int mid = (begin + end) / 2;
		if (begin >= count) break;

		if (mid <= count) {
			if (end - begin > 1)
				sum += pool[lista+1].sum;

			begin = mid;
			lista = pool[lista].right;
		} else {
			end = mid;
			++lista;
		}
	}

	return sum;
}

void mix(int first, int second, int begin, int end, int count) {
	++query_count;

	// assert(first->begin == second->begin);
	// assert(first->end == second->end);

	if (end <= count) {
		// intervalul e in partea stanga a liniei
		return;
	}

	const int mid = (begin + end) / 2;

	if (mid >= count) {
		// partea dreapta trebuie intershimbata
		mix(first + 1, second + 1, begin, mid, count);
		swap(pool[first].right, pool[second].right);
	} else {
		mix(pool[first].right, pool[second].right, mid, end, count);
	}

	// facem update la suma
	pool[first].update();
	pool[second].update();
}

void recursive_print_square(int lista, int begin, int end, bool dir) {
	if (lista == INFI) return;

	if (end - begin == 1) {
		printf("%d ", pool[lista].sum);
		return;
	} else {
		const int mid = (begin + end) / 2;

		if (dir) {
			recursive_print_square(pool[lista].right, mid, end, dir);
			recursive_print_square(lista + 1, begin, mid, dir);
		} else {
			recursive_print_square(lista + 1, begin, mid, dir);
			recursive_print_square(pool[lista].right, mid, end, dir);
		}
	}
}

void print_square() {
	for (int i = 0; i < N; ++i) {
		if (i != 0)
			recursive_print_square(lst[i][0], 0, N, true);

		printf("%d ", dia[i]);

		if (i != N-1)
			recursive_print_square(lst[i][1], 0, N, false);

		printf("\n");
	}
}

int main() {
	freopen("eprubeta.in", "rt", stdin);
	freopen("eprubeta.out", "wt", stdout);

	scanf("%d %d", &N, &M);

	int X, A, B;
	scanf("%d %d %d", &X, &A, &B);

	for (int i = 0; i < N; ++i) {
		int line[maxN];
		for (int j = 0; j < N; ++j)
			line[j] = ((i + A) * (j + B) / 4) % X;

		dia[i] = line[i];
		lst[i][0] = lst[i][1] = INFI;

		// creem prima lista (stanga)
		if (i != 0) {
			int temp[maxN] = { 0 };
			copy(line, line + i, temp);
			reverse(temp, temp + i);

			lst[i][0] = create(temp, 0, N, i);
		}

		// creem a doua lista (dreapta)
		if (i != N-1) {
			int temp[maxN] = { 0 };
			copy(line + i + 1, line + N, temp);

			lst[i][1] = create(temp, 0, N, N - i - 1);
		}
	}

	fprintf(stderr, "pool_head = %d\n", pool_head);

	for (int i = 0; i < M; ++i) {
		int o, a, b;
		scanf("%d %d %d", &o, &a, &b);

		// verificam conditiile
		assert(0 <= a && a < N);
		assert(0 <= b && b < N);
		assert(o == 1 || o == 2);
		assert(a <= b);

		// executam operatiile
		if (o == 1) {
			int l = b-a+1;
			for (int j = 0; j < l-1; ++j) {
				mix(lst[a+j][1], lst[b-j][0], 0, N, l-j-1);
				swap(lst[a+j][1], lst[b-j][0]);
			}

			reverse(dia + a, dia + b + 1);
		} else {
			// interogare
			int sum = 0;

			for (int j = a; j <= b; ++j) {
				sum += dia[j];

				if (j > a) sum += query(lst[j][0], j - a);
				if (j < b) sum += query(lst[j][1], b - j);
			}

			printf("%d\n", sum);
		}
	}

	fprintf(stderr, "qc = %d\n", query_count);

	unsigned int result = 0;
	for (int i = 0; i < N; ++i) {
		unsigned int sum = 0;

		sum += dia[i];
		if (i != 0) sum += pool[lst[i][0]].sum;
		if (i != N-1) sum += pool[lst[i][1]].sum;

		result += sum * sum * (i + 1);
	}
	printf("%u\n", result);

	return 0;
}