Submission #261346

#TimeUsernameProblemLanguageResultExecution timeMemory
261346user202729Palembang Bridges (APIO15_bridge)C++17
41 / 100
36 ms2688 KiB
// 4
// failed.
//
//
// Why 10000 bytes...
#ifndef LOCAL
#define NDEBUG 1
#endif
#include<bits/stdc++.h>


template <class Node, class Detail>struct SegmentTreeTemplate{std::vector<Node> data;SegmentTreeTemplate(){}SegmentTreeTemplate(int number){assign(number);}SegmentTreeTemplate(std::size_t number){assign(number);}SegmentTreeTemplate(int number,Node const& node){assign(number,node);}void assign(int number){assign(number,Node{});}void assign(int number,Node const& node){assign(number,[&]{return node;});}void assign(int number,auto const& generator){data.reserve(number*2);data.resize(number);for(int i=0;i<number;++i) {if(data.size()>=data.capacity()) __builtin_unreachable();if constexpr(std::is_invocable_v<decltype(generator),int>){data.push_back(generator(i));}else{data.push_back(generator());}}for(int i=number;--i;) Detail::template combine<true>(data[i],data[i<<1],data[i<<1|1]);}private:static bool evaluatesToTrue(auto const& fn){if constexpr(std::is_same_v<decltype(fn()),void>){fn();return false;}else{return fn();}}
#define IS_TRUE(expr...) evaluatesToTrue([&]{return (expr);})
template<class F,class T>static decltype(auto) invokeWithOptionalLayer(F const& f,T&& t,int layer) {if constexpr(std::is_invocable_v<F,T&&>) return f(std::forward<T>(t));else return f(std::forward<T>(t),layer);}public:static void forStrictAncestorIndexDown(int node,auto const& fn){for(int shift=31^__builtin_clz(node);shift;--shift)if(IS_TRUE(fn(node>>shift))) break;}static void forStrictAncestorIndexUp(int node,auto const& fn){for(int y=node>>1;y;y>>=1)if(IS_TRUE(fn(y))) break;}static void forRangeIndex(int leftNode,int rightNode,auto const& leftfn,auto const& rightfn){int layer=0;while(leftNode<rightNode){if(leftNode&1) if(IS_TRUE(invokeWithOptionalLayer(leftfn,leftNode++,layer))) break;if(rightNode&1) if(IS_TRUE(invokeWithOptionalLayer(rightfn,--rightNode,layer))) break;leftNode>>=1;rightNode>>=1;++layer;}}
#undef IS_TRUE
int offset()const{return int(data.size()/2u);}void combineAll(int node){assert(node>=offset());forStrictAncestorIndexUp(node,[&](int it){Detail::template combine<false>(data[it],data[it<<1],data[it<<1|1]);});}void forRange(int leftNode,int rightNode,auto const& leftfn,auto const& rightfn){assert(leftNode>=offset());assert(rightNode>=offset());forRangeIndex(leftNode,rightNode,[&](auto it,auto layer){return invokeWithOptionalLayer(leftfn,data[it],layer);},[&](auto it,auto layer){return invokeWithOptionalLayer(rightfn,data[it],layer);});}void forRange(int leftNode,int rightNode,auto const& fn){forRange(leftNode,rightNode,fn,fn);}template<class T> T reduceRange(int leftNode,int rightNode,T initial,auto const& function) {forRange(leftNode,rightNode,[&](Node const& node){initial=function(std::move(initial),node);});return initial;}};

struct Node{ int count; int64_t sum; };
struct SegmentTree: SegmentTreeTemplate<Node, SegmentTree>{
	using SegmentTreeTemplate::SegmentTreeTemplate;
	
	static void push(Node&, Node&){ }
	template<bool first>
	static void combine(Node& parent, Node const& left, Node const& right){ 
		parent.count=left.count+right.count;
		parent.sum=left.sum+right.sum;
	}

	// other methods
	void set(int node, Node value){
		data[node]=value; combineAll(node);
	}
	void add(int index, int64_t value){
		int node=index+offset();
		set(node, {data[node].count+1, data[node].sum+value});
	}
	void remove(int index, int64_t value){
		int node=index+offset();
		assert(data[node].count); assert(data[node].sum>=value);
		set(node, {data[node].count-1, data[node].sum-value});
	}

	Node get(int left, int right){
		left+=offset(); right+=offset();
		return reduceRange(left, right, Node{}, [](Node result, Node node){
			Node next; combine<true>(next, result, node); return next;
		});
	}

	int extract(int node, int pos) const{
		assert(0<=pos and pos<=data[node].count);
		if(pos==data[node].count){pos=0;++node;}
		while(node<offset()){
			node<<=1;
			if(pos>=data[node].count){
				pos-=data[node++].count;
			}
		}
		return node;
	}

	int center(int left, int right){
		auto const count=get(left, right).count;
		if(count==0) return left;
		assert(count%2==0); assert(count!=0);
		int result=-1;
		int left_=count/2, right_=count/2;
		forRangeIndex(left+offset(), right+offset(),[&](int node){
			if(data[node].count>=left_){
				assert(result<0);
				result=extract(node, left_);
				return true;
			}
			left_-=data[node].count;
			return false;
		},[&](int node){
			if(data[node].count>=right_){
				assert(result<0);
				result=extract(node, data[node].count-right_);
				return true;
			}
			right_-=data[node].count;
			return false;
		});
		assert(result>=offset());
		if(result==offset()*2) result>>=1;
		result-=offset();

		assert(left<=result and result<=right);
		assert(get(left, result).count==count/2);
		assert(get(result, right).count==count/2);
		return result;
	}
};

struct Function{
	std::vector<int64_t> allValues;
	SegmentTree tree;

	void build(){
		std::sort(begin(allValues), end(allValues));
		allValues.erase(std::unique(begin(allValues), end(allValues)), end(allValues));

		assert(tree.data.empty());
		tree.assign((int)allValues.size());
	}

	int64_t factor{};
	
	void fakeAdd(std::pair<int, int> it){
		allValues.push_back(it.first);
		allValues.push_back(it.second);
	}

	void add(std::pair<int, int> it){
		factor+=it.second-it.first;
		assert(it.first<it.second);
		for(auto it: {it.first, it.second}){
			tree.add(int(std::lower_bound(begin(allValues), end(allValues), it)-begin(allValues)), it);
		}
	}
	void remove(std::pair<int, int> it){
		factor-=it.second-it.first;
		assert(factor>=0);
		assert(it.first<it.second);
		for(auto it: {it.first, it.second}){
			tree.remove(int(std::lower_bound(begin(allValues), end(allValues), it)-begin(allValues)), it);
		}
	}
	int64_t calculateTwice(int64_t twicePos) {
		auto info=tree.get(
				int(std::upper_bound(begin(allValues), end(allValues), twicePos/2)-allValues.begin()),
				tree.offset());
		auto [countAll, sumAll]=tree.data[1];
		assert(countAll%2==0);
		assert(info.count<=countAll);

		int64_t result=-sumAll+info.sum*2+twicePos*(countAll/2-info.count);
		assert(([&]{
			int64_t naive{};
			for(int index=0; index<tree.offset(); ++index){
				auto const c=tree.data[index+tree.offset()].count;
				assert(c>=0);
				naive+=c*(
						std::abs(allValues[index]*2-twicePos)
						);
			}
			assert(naive%2==0); naive/=2;
			assert(naive==result);
			return true;
		}()));
		return result-factor;
	}
	int64_t calculate(int64_t pos){return calculateTwice(pos*2);}
	int64_t minPos() {
		return allValues[tree.center(0, tree.offset())];
	}

};

int main(){
	std::ios::sync_with_stdio(0);std::cin.tie(0);
	int numBridge, numPeople; std::cin>>numBridge>>numPeople;
	int64_t base{};
	std::vector<std::pair<int, int>> terms; terms.reserve(numPeople);
	for(int _=0; _<numPeople; ++_){
		char side1, side2; int pos1, pos2;
		std::cin>>side1>>pos1>>side2>>pos2;
		std::tie(pos1, pos2)=std::minmax({pos1, pos2});
		if(side1==side2) base+=pos2-pos1;
		else {
			base+=pos2-pos1+1;
			terms.push_back({pos1, pos2});
		}
	}
	assert((int)terms.size()<=numPeople);
	if(terms.empty()){std::cout<<base<<'\n'; return 0;}

	std::vector<int> positions; positions.reserve(terms.size()*2);
	for(auto [first, sec]: terms){
		positions.push_back(first); positions.push_back(sec);
	}
	std::sort(begin(positions), end(positions));
	positions.erase(std::unique(begin(positions), end(positions)), end(positions));

	auto const center=[&](auto it){return it.first+it.second;};
	if(numBridge==2 and numPeople<=1000){
		std::sort(begin(terms), end(terms),[&](auto first, auto sec){
			return center(first)<center(sec);
		});
		auto result=INT64_MAX;

		Function sumFunction, diffFunction, added, addFlipped;

		for(auto t: terms){
			sumFunction.fakeAdd(t);
			added.fakeAdd(t);
			addFlipped.fakeAdd(t);

			diffFunction.fakeAdd(t);
			addFlipped.fakeAdd({-t.second, t.first});
		}
		sumFunction.build();
		diffFunction.build();
		added.build();
		addFlipped.build();
		for(auto t: terms){
			sumFunction.add(t);
			added.add(t);
			addFlipped.add(t);
		}


		for(int index=0; index<=(int)terms.size(); ++index){
			int twicedleft=index==0 ? INT_MIN: center(terms[index-1]);
			int twicedright=index==(int)terms.size() ? INT_MAX: center(terms[index]);
			// consider d in [twicedleft/2..twicedright/2]
			// left terms=(0..index), right terms=(index..(int)terms.size())
			
			if(index!=0){
				auto t=terms[index-1];

				diffFunction.add(t);
				addFlipped.add({-t.second, t.first});

				sumFunction.remove(t);
				addFlipped.remove(t);
			}

			auto sum1=sumFunction.minPos(), diff1=diffFunction.minPos(); // d+r, d-r
			auto twiced=sum1+diff1, twicer=sum1-diff1;
			if(twicer>=0 and twicedleft<=twiced and twiced<=twicedright){
				result=std::min(result, sumFunction.calculate(sum1)+diffFunction.calculate(diff1));
			}
			else if(twicer<0){
				auto const twiced=std::max((int64_t)twicedleft,
						std::min((int64_t)twicedright, (int64_t)added.minPos()*2));
				result=std::min(result, sumFunction.calculateTwice(twiced)+diffFunction.calculateTwice(twiced));
			}
			else if(twiced<twicedleft){
				auto const twicer=std::max<int64_t>(0, twicedleft+(int64_t)addFlipped.minPos()*2);
				result=std::min(result, sumFunction.calculateTwice(twicedleft+twicer)+
						diffFunction.calculateTwice(twicedleft-twicer));
			}
			else if(twiced>twicedright){
				auto const twicer=std::max<int64_t>(0, twicedright+(int64_t)addFlipped.minPos()*2);
				result=std::min(result, sumFunction.calculateTwice(twicedright+twicer)+
						diffFunction.calculateTwice(twicedright-twicer));
			}
		}
		std::cout<<result+base<<'\n';
	}
}
#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...