제출 #151592

#제출 시각아이디문제언어결과실행 시간메모리
151592mieszko11bRectangles (IOI19_rect)C++14
100 / 100
4658 ms974168 KiB
#include <bits/stdc++.h>
#include "rect.h"

using namespace std;

struct rect {
	int x1, x2, y1, y2;
	bool ok;
	
	rect() {};
	rect(int x1, int x2, int y1, int y2) {
		this->x1 = x1;
		this->x2 = x2;
		this->y1 = y1;
		this->y2 = y2;
		this->ok = true;
	}
};

bool operator<(const rect &a, const rect &b) {
	return make_tuple(a.x1, a.x2, a.y1, a.y2) < make_tuple(b.x1, b.x2, b.y1, b.y2);
}

bool operator==(const rect &a, const rect &b) {
	return make_tuple(a.x1, a.x2, a.y1, a.y2) == make_tuple(b.x1, b.x2, b.y1, b.y2);
}

int n, m;
int A[2507][2507], newA[2507][2507];
int L[2507][2507], R[2507][2507], U[2507][2507], D[2507][2507];
int LM[20][2507][2507];
int cnt[2507];
int ok_pow[2507];
vector<rect> candidates;

bool less_op(int a, int b) {
	return a < b;
}

bool less_equal_op(int a, int b) {
	return a <= b;
}

inline bool okx(int x) {
	return x >= 1 && x <= n;
}

inline bool oky(int y) {
	return y >= 1 && y <= m;
}

void calc_firsts(bool (*op)(int, int) ) {
	for(int x = 1 ; x <= n ; x++) {
		stack<int> S;
		for(int y = 1 ; y <= m ; y++) {
			while(!S.empty() && op(A[x][S.top()], A[x][y]))
				S.pop();
			if(S.empty())
				L[x][y] = 0;
			else
				L[x][y] = S.top();
			S.push(y);
		}
	}
	
	for(int x = 1 ; x <= n ; x++) {
		stack<int> S;
		for(int y = m ; y >= 1 ; y--) {
			while(!S.empty() && op(A[x][S.top()], A[x][y]))
				S.pop();
			if(S.empty())
				R[x][y] = m + 1;
			else
				R[x][y] = S.top();
			S.push(y);
		}
	}
	
	for(int y = 1 ; y <= m ; y++) {
		stack<int> S;
		for(int x = 1 ; x <= n ; x++) {
			while(!S.empty() && op(A[S.top()][y], A[x][y]))
				S.pop();
			if(S.empty())
				U[x][y] = 0;
			else
				U[x][y] = S.top();
			S.push(x);
		}
	}

	for(int y = 1 ; y <= m ; y++) {
		stack<int> S;
		for(int x = n ; x >= 1 ; x--) {
			while(!S.empty() && op(A[S.top()][y], A[x][y]))
				S.pop();
			if(S.empty())
				D[x][y] = n + 1;
			else
				D[x][y] = S.top();
			S.push(x);
		}
	}
}

void find_candidates() {
	for(int x = 1 ; x <= n ; x++) {
		for(int y = 1 ; y <= m ; y++) {
			int x1 = U[x][y];
			int x2 = D[x][y];
			int y1 = L[x][y];
			int y2 = R[x][y];
			
			if(okx(x1) && okx(x2) && oky(y1) && oky(y2) && x1 + 1 < x2 && y1 + 1 < y2)
				candidates.emplace_back(x1 + 1, x2 - 1, y1 + 1, y2 - 1);
		}
	}
}

int maxv(int x1, int x2, int y) {
	int p = ok_pow[x2 - x1 + 1];
	return max(LM[p][x1][y], LM[p][x2 - (1 << p) + 1][y]);
}

void calc_left() {
	for(int x = 1 ; x <= n ; x++) {
		stack<int> S;
		for(int y = 1 ; y <= m ; y++) {
			while(!S.empty() && A[x][S.top()] < A[x][y])
				S.pop();
			if(S.empty())
				LM[0][x][y] = L[x][y] = 0;
			else
				LM[0][x][y] = L[x][y] = S.top();
			S.push(y);
		}
	}
	
	for(int k = 1 ; k < 20 ; k++)
		for(int x = 1 ; x <= n ; x++)
			for(int y = 1 ; y <= m ; y++)
				LM[k][x][y] = max(LM[k - 1][x][y], okx(x + (1 << (k - 1))) ? LM[k - 1][x + (1 << (k - 1))][y] : 0);
}

void one_check() {
	calc_left();
	for(rect &r : candidates) {
		if(maxv(r.x1, r.x2, r.y2 + 1) >= r.y1)
			r.ok = false;
	}
}

void mirror_swap() {
	for(int x = 1 ; x <= n ; x++)
		reverse(A[x] + 1, A[x] + m + 1);
	for(rect &r : candidates) {
		swap(r.y1, r.y2);
		r.y1 = m - r.y1 + 1;
		r.y2 = m - r.y2 + 1;
	}
}

void swap_dim() {
	for(int x = 1 ; x <= n ; x++)
		for(int y = 1 ; y <= m ; y++)
			newA[y][x] = A[x][y];
			
	for(int x = 1 ; x <= n ; x++)
		for(int y = 1 ; y <= m ; y++)
			A[y][x] = newA[y][x];
			
	for(rect &r : candidates) {
		swap(r.x1, r.y1);
		swap(r.x2, r.y2);
	}
			
	swap(n, m);
}

int count() {
	int res = 0;
	for(rect r : candidates)
		if(r.ok)
			res++;
			
	return res;
}

long long count_rectangles(std::vector<std::vector<int> > a) {
	n = a.size();
	m = a[0].size();
	
	int pot = 0;
	for(int i = 1 ; i <= max(n, m) ; i++) {
		if((1 << (pot+1)) <= i)
			pot++;
		ok_pow[i] = pot;
	}
	
	for(int i = 0 ; i < n ; i++)
		for(int j = 0 ; j < m ; j++)
			A[i + 1][j + 1] = a[i][j];
			
	calc_firsts(less_equal_op);
	find_candidates();
	
	//sort(candidates.begin(), candidates.end());
	
	vector<rect> ncand;
	int smaller;
	
	memset(cnt, 0, sizeof cnt);
	for(rect r : candidates)
		cnt[r.x1]++;
	smaller = 0;
	for(int i = 0 ; i < 2507 ; i++) {
		int d = cnt[i];
		cnt[i] = smaller;
		smaller += d;
	}
	ncand.resize(candidates.size());
	for(rect r : candidates)
		ncand[cnt[r.x1]++] = r;
	swap(ncand, candidates);
	
	memset(cnt, 0, sizeof cnt);
	for(rect r : candidates)
		cnt[r.x2]++;
	smaller = 0;
	for(int i = 0 ; i < 2507 ; i++) {
		int d = cnt[i];
		cnt[i] = smaller;
		smaller += d;
	}
	ncand.resize(candidates.size());
	for(rect r : candidates)
		ncand[cnt[r.x2]++] = r;
	swap(ncand, candidates);
	
	memset(cnt, 0, sizeof cnt);
	for(rect r : candidates)
		cnt[r.y1]++;
	smaller = 0;
	for(int i = 0 ; i < 2507 ; i++) {
		int d = cnt[i];
		cnt[i] = smaller;
		smaller += d;
	}
	ncand.resize(candidates.size());
	for(rect r : candidates)
		ncand[cnt[r.y1]++] = r;
	swap(ncand, candidates);
	
	memset(cnt, 0, sizeof cnt);
	for(rect r : candidates)
		cnt[r.y2]++;
	smaller = 0;
	for(int i = 0 ; i < 2507 ; i++) {
		int d = cnt[i];
		cnt[i] = smaller;
		smaller += d;
	}
	ncand.resize(candidates.size());
	for(rect r : candidates)
		ncand[cnt[r.y2]++] = r;
	swap(ncand, candidates);
	
	candidates.resize(distance(candidates.begin(), unique(candidates.begin(), candidates.end())));
	
	one_check();
	
	//cout << count() << endl;
	mirror_swap();
	one_check();
	//cout << count() << endl;
	swap_dim();

	one_check();
	//cout << count() << endl;
	mirror_swap();
	one_check();
			
	return count();
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...