Language: C++

#include <cstdint>
#include <string>
#include <vector>
#include <iostream>
#include <iterator>
#include <cassert>
#include <algorithm>
#include <utility>
#include <initializer_list>
#include <iomanip>
#include <type_traits>
namespace loquat {
namespace bitmanip {
template <typename T>
inline auto clz(T x) noexcept ->
	typename std::enable_if<sizeof(int) < sizeof(T), unsigned int>::type
{
	return __builtin_clzll(x);
}
template <typename T>
inline auto popcount(T x) noexcept ->
	typename std::enable_if<sizeof(T) <= sizeof(int), unsigned int>::type
{
	return __builtin_popcount(x);
}
template <typename T>
inline auto popcount(T x) noexcept ->
	typename std::enable_if<sizeof(int) < sizeof(T), unsigned int>::type
{
	return __builtin_popcountll(x);
}
template <typename T>
inline T clp2(T x) noexcept {
	if(x == 0u){ return 0u; }
	return T(1u) << (sizeof(T) * 8u - clz(x - 1));
}
template <typename T>
inline T flp2(T x) noexcept {
	if(x == 0u){ return 0u; }
	return T(1u) << (sizeof(T) * 8u - 1u - clz(x));
}
}
}
namespace loquat {
template <typename Behavior>
class segment_tree {
public:
	using behavior_type = Behavior;
	using value_type = typename behavior_type::value_type;
private:
	size_t m_actual_size;
	std::vector<value_type> m_values;
	behavior_type m_behavior;
	void initialize(){
		const auto m = m_values.size() / 2;
		for(size_t i = 0; i < m; ++i){
			const auto k = m - 1 - i;
			m_values[k] = m_behavior.merge(
				m_values[k * 2 + 1], m_values[k * 2 + 2]);
		}
	}
public:
	segment_tree(
		size_t size,
		const behavior_type& behavior = behavior_type())
		: m_actual_size(size)
		, m_values(bitmanip::clp2(m_actual_size) * 2 - 1)
		, m_behavior(behavior)
	{
		const auto it = m_values.begin() + m_values.size() / 2;
		std::fill(it, it + m_actual_size, value_type());
		initialize();
	}
	const value_type& operator[](size_t i) const {
		return m_values[m_values.size() / 2 + i];
	}
	void update(size_t i, const value_type& x){
		i += m_values.size() / 2;
		m_values[i] = x;
		while(i > 0){
			i = (i - 1) / 2;
			m_values[i] = m_behavior.merge(
				m_values[i * 2 + 1], m_values[i * 2 + 2]);
		}
	}
	value_type query(size_t left, size_t right) const {
		const auto m = m_values.size() / 2;
		left += m; right += m;
		value_type l_value = m_behavior.identity(), r_value = l_value;
		while(left < right){
			if((left & 1u) == 0u){
				const auto& x = m_values[left];
				l_value = m_behavior.merge(l_value, x);
			}
			if((right & 1u) == 0u){
				const auto& x = m_values[right - 1];
				r_value = m_behavior.merge(x, r_value);
			}
			left  = left / 2;
			right = (right - 1) / 2;
		}
		return m_behavior.merge(l_value, r_value);
	}
};
}
using namespace std;
using pii = pair<int, int>;
static const int INF = 1000000000;
struct range_query_behavior {
	using value_type = int;
	value_type identity() const { return -INF; }
	value_type merge(const value_type& a, const value_type& b) const {
		return max(a, b);
	}
};
int main(){
	ios_base::sync_with_stdio(false);
	cout << setiosflags(ios::fixed) << setprecision(20);
	int x1, y1, x2, y2, n;
	cin >> x1 >> y1 >> x2 >> y2 >> n;
	if(y1 > y2){
		swap(x1, x2);
		swap(y1, y2);
	}
	const int min_x = min(x1, x2), max_x = max(x1, x2);
	vector<pii> points;
	for(int i = 0; i < n; ++i){
		int x, y;
		cin >> x >> y;
		if(y < y1 || y2 < y){ continue; }
		if(x < min_x || max_x < x){ continue; }
		if(x1 < x2){
			points.emplace_back(y - y1, x - x1);
		}else{
			points.emplace_back(y - y1, x1 - x);
		}
	}
	const int w = max_x - min_x, h = y2 - y1;
	if(w == 0 || h == 0){
		double answer = (w + h) * 100.0;
		if(!points.empty()){ answer += (20 * M_PI / 2 - 20); }
		cout << answer << endl;
		return 0;
	}
	vector<int> xc = { 0, w, w + 1 };
	for(const auto& p : points){
		xc.push_back(p.second);
		xc.push_back(p.second + 1);
	}
	sort(xc.begin(), xc.end());
	xc.erase(unique(xc.begin(), xc.end()), xc.end());
	loquat::segment_tree<range_query_behavior> st(xc.size());
	st.update(0, 0);
	for(const auto& p : points){
		const int xx = lower_bound(xc.begin(), xc.end(), p.second) - xc.begin();
		const int val = st[xx];
		const int mv = st.query(0, xx), mh = max(mv, val);
		st.update(xx, mv + 1);
		st.update(xx + 1, max(st[xx + 1], mh + 1));
	}
	const double reduce = max(
		(20 - 20 * M_PI / 4) * st.query(0, xc.size() - 1),
		(20 - 20 * M_PI / 4) * st.query(0, xc.size()) - (20 * M_PI / 2 - 20));
	const double answer = (w + h) * 100.0 - reduce;
	cout << answer << endl;
	return 0;
}


Compiler output:
a.cc: In function 'int main()':
a.cc:141:54: error: 'M_PI' was not declared in this scope
  141 |                 if(!points.empty()){ answer += (20 * M_PI / 2 - 20); }
      |                                                      ^~~~
a.cc:162:28: error: 'M_PI' was not declared in this scope
  162 |                 (20 - 20 * M_PI / 4) * st.query(0, xc.size() - 1),
      |                            ^~~~