제출 #286069

#제출 시각아이디문제언어결과실행 시간메모리
286069user202729Rectangles (IOI19_rect)C++17
72 / 100
5078 ms343356 KiB
// moreflags=grader.cpp
// 13
// .........
#include "rect.h"
#include<vector>
#include<set>
#include<algorithm>
#if not LOCAL
#define NDEBUG
#endif
#include<cassert>

long long count_rectangles(std::vector<std::vector<int> > a) {
	if(a.size()<3 or a[0].size()<3) return 0;

	struct T{ int right, depth; };
	using std::begin; using std::end;
	struct Vector{
		T* begin_;
		T* end_;
		T* begin() const{return begin_;}
		T* end() const{return end_;}
		void push_back(T it){ *end_++=it; }
		int size() const{return int(end_-begin_);}
	};
	using Segments=std::vector<Vector>;
	std::vector<T> buffer; buffer.reserve(a.size()*a[0].size()*2);

	auto const getSegments=[&](std::vector<int> const& data)->Segments{
		Segments result(data.size()-1); // [l] -> list of valid r in reverse sorted order

		struct Item{int value, index;};
		std::vector<Item> items(data.size());
		for(int index=0; index<(int)items.size(); ++index)
			items[index]={data[index], index};
		std::sort(begin(items), end(items),[&](Item first, Item sec){return first.value>sec.value;});

		static std::set<int> done;
		static std::vector<std::set<int>::node_type> segments;
		if(segments.empty()){
			for(int i=0; i<(int)std::max(a.size(), a[0].size()); ++i){
				done.insert(i);
				segments.push_back(done.extract(done.begin()));
			}
		}
		assert(done.empty());

		for(auto real: {false, true}){
			assert(sizeof(Segments::value_type)>=sizeof(int));
			if(not real)
			for(auto& it: result)
				assert(reinterpret_cast<int&>(it)==0);

			for(auto [value, index]: items){
				auto const [iterator, inserted, _nodeHandle]=done.insert(std::move(segments[index]));
				assert(inserted);
				auto const next=std::next(iterator);
				if(iterator!=done.begin() and next!=done.end())
					if(auto const prevValue=*std::prev(iterator); value<data[prevValue] and value<data[*next]){
						if(real){
							//if(result[prevValue+1].size()>=result[prevValue+1].capacity()){ assert(false); __builtin_unreachable(); }
							result[prevValue+1].push_back(T{*next, 1});
						}else
							++reinterpret_cast<int&>(result[prevValue+1]);
					}
			}

			if(not real)
			for(auto& it: result){
				int const size=reinterpret_cast<int&>(it);
				reinterpret_cast<int&>(it)=0;
				it.begin_=it.end_=buffer.data()+buffer.size();
				for(int _=0; _<size; ++_){
					if(buffer.size()>=buffer.capacity()){ assert(false); __builtin_unreachable(); }
					buffer.push_back({});
				}
			}

			for(int index=0; index<(int)items.size(); ++index){
				assert(*done.begin()==index);
				segments[index]=done.extract(done.begin());
			}
		}

		for(auto& it: result)
			assert(std::is_sorted(begin(it), end(it), [&](T first, T sec){return first.right>sec.right;}));

		return result;
	};

	std::vector<Segments> rows(a.size()-1), cols(a[0].size()-1);
	for(int row=1; row<(int)a.size()-1; ++row)
		rows[row]=getSegments(a[row]);
	{
		std::vector<int> tmp(a.size());
		for(int col=1; col<(int)a[0].size()-1; ++col){
			std::transform(begin(a), end(a), tmp.begin(),[&](std::vector<int> const& it){return it[col];});
			cols[col]=getSegments(tmp);
		}
	}

	auto const computeDepth=[&](std::vector<Segments>& data)->void{
		if(data.size()<=2) return;
		assert(data[0].empty()); // this is confusing.

		for(int row=(int)data.size()-1; --row;){
			for(int left=0; left<(int)data[row].size(); ++left){
				auto const& v=data[row+1][left];
				for(auto& [right, depth]: data[row][left]){
					assert(depth==1);
					auto const iterator=std::upper_bound(begin(v), end(v), right,
							[&](int right, T item){ return item.right<=right; });
					if(iterator!=v.end() and iterator->right==right)
						depth=iterator->depth+1;
					else{
						assert(iterator==v.end() or iterator->right<right);
						assert(iterator==v.begin() or iterator->right>right);
						assert(std::is_sorted(begin(v), end(v), [&](T first, T sec){return first.right>sec.right;}));
					}
				}
			}
		}
	};

	computeDepth(rows);
	computeDepth(cols);

	struct Bit{
		std::vector<int> data;
		Bit(int number){reset(number);}
		void reset(int number){data.assign(number, 0);}
		void add(int index, int value){
			for(; index>=0; index=(index&(index+1))-1)
				data[index]+=value;
		}
		int sumSuffix(int index) const{
			int result{};
			for(; index<(int)data.size(); index|=index+1)
				result+=data[index];
			return result;
		}
	};
	Bit bit((int)a[0].size()-1);

	enum class EventType{ add, get };
	struct Event{ EventType type; int x, y;
		bool operator<(Event other) const{return std::tie(y, type)<std::tie(other.y, other.type);}
	};
	std::vector<Event> events;
	std::vector<int> xs;

	int64_t result{};
	for(int up=1; up<(int)a.size()-1; ++up)
	for(int left=1; left<(int)a[0].size()-1; ++left){
		auto const A=(int)rows[up][left].size(), B=(int)cols[left][up].size();

		if(A*B<=((31^__builtin_clz(A+B+4)))*(A+B)){
			for(auto [right, depthDown]: rows[up][left])
			for(auto [down, depthRight]: cols[left][up])
				if(depthDown>=down-up and depthRight>=right-left)
					++result;
		}else{
			events.clear();
			xs.clear();
			for(auto [right, depthDown]: rows[up][left]){
				events.push_back({EventType::get, right-left, depthDown});
				xs.push_back(right-left);
			}
			for(auto [down, depthRight]: cols[left][up]){
				events.push_back({EventType::add, depthRight, down-up});
				xs.push_back(depthRight);
			}
			std::sort(begin(events), end(events));
			std::sort(begin(xs), end(xs));
			xs.erase(std::unique(begin(xs), end(xs)), end(xs));

			bit.reset(xs.size());
			for(auto [type, x, y]: events){
				x=int(std::lower_bound(begin(xs), end(xs), x)-begin(xs));
				if(type==EventType::add){
					bit.add(x, 1);
				}else{
					result+=bit.sumSuffix(x);
				}
			}
		}
	}
	return result;
}

컴파일 시 표준 에러 (stderr) 메시지

rect.cpp: In lambda function:
rect.cpp:51:14: warning: unused variable 'it' [-Wunused-variable]
   51 |    for(auto& it: result)
      |              ^~
rect.cpp:85:13: warning: unused variable 'it' [-Wunused-variable]
   85 |   for(auto& it: result)
      |             ^~
#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...