제출 #1338587

#제출 시각아이디문제언어결과실행 시간메모리
1338587ZicrusTiles (BOI24_tiles)C++20
100 / 100
135 ms15604 KiB
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<vector<ll>> vvl;
const ll inf = LONG_LONG_MAX / 2;

template <class T> int sgn(T x) { return (x > 0) - (x < 0); }
template<class T>
struct Point {
	typedef Point P;
	T x, y;
	explicit Point(T x=0, T y=0) : x(x), y(y) {}
	bool operator<(P p) const { return tie(x,y) < tie(p.x,p.y); }
	bool operator==(P p) const { return tie(x,y)==tie(p.x,p.y); }
	P operator+(P p) const { return P(x+p.x, y+p.y); }
	P operator-(P p) const { return P(x-p.x, y-p.y); }
	P operator*(T d) const { return P(x*d, y*d); }
	P operator/(T d) const { return P(x/d, y/d); }
	T dot(P p) const { return x*p.x + y*p.y; }
	T cross(P p) const { return x*p.y - y*p.x; }
	T cross(P a, P b) const { return (a-*this).cross(b-*this); }
	T dist2() const { return x*x + y*y; }
	double dist() const { return sqrt((double)dist2()); }
	// angle to x-axis in interval [-pi, pi]
	double angle() const { return atan2(y, x); }
	P unit() const { return *this/dist(); } // makes dist()=1
	P perp() const { return P(-y, x); } // rotates +90 degrees
	P normal() const { return perp().unit(); }
	// returns point rotated 'a' radians ccw around the origin
	P rotate(double a) const {
		return P(x*cos(a)-y*sin(a),x*sin(a)+y*cos(a)); }
	friend ostream& operator<<(ostream& os, P p) {
		return os << "(" << p.x << "," << p.y << ")"; }
};
typedef Point<ll> P;

template<class T>
T polygonArea2(vector<Point<T>>& v) {
	T a = v.back().cross(v[0]);
	rep(i,0,sz(v)-1) a += v[i].cross(v[i+1]);
	return a;
}

struct event {
    ll x, l, r;
    bool stop;

    event(ll x, ll l, ll r, bool stop) : x(x), l(l), r(r), stop(stop) { }

    bool operator<(const event &o) const {
        return x < o.x;
    }
};

struct segtree {
    struct node {
        bool lp = false, rp = false, mp = false, has = false, full = false;
        bool lazy = false, lz_val = false;
    };
    ll nt = 0;
    vector<node> tree;

    segtree(ll n) {
        nt = 1;
        while (nt < n) nt *= 2;
        tree = vector<node>(2*nt);
    }

    void prop(ll k) {
        if (!tree[k].lazy) return;
        tree[k].has = tree[k].full = tree[k].lz_val;
        tree[k].mp = false;
        if (!tree[k].lz_val) tree[k].lp = tree[k].rp = false;
        else tree[k].lp = tree[k].rp = (k >= nt);
        if (k < nt) {
            tree[2*k].lazy = tree[2*k+1].lazy = true;
            tree[2*k].lz_val = tree[2*k+1].lz_val = tree[k].lz_val;
        }
        tree[k].lazy = false;
    }

    void recalc(ll k) {
        if (k >= nt) return;
        tree[k].has = tree[2*k].has || tree[2*k+1].has;
        tree[k].full = tree[2*k].full && tree[2*k+1].full;
        if (tree[2*k].full && tree[2*k+1].full) {
            tree[k].lp = tree[k].rp = tree[k].mp = false;
        }
        else if (!tree[2*k].full && !tree[2*k+1].full) {
            tree[k].lp = tree[2*k].lp;
            tree[k].rp = tree[2*k+1].rp;
            tree[k].mp = tree[2*k].mp || tree[2*k+1].mp || (tree[2*k].rp != tree[2*k+1].lp);
        }
        else if (tree[2*k].full && !tree[2*k+1].full) {
            tree[k].lp = (tree[2*k].lp != tree[2*k+1].lp);
            tree[k].rp = tree[2*k+1].rp;
            tree[k].mp = tree[2*k+1].mp;
        }
        else if (!tree[2*k].full && tree[2*k+1].full) {
            tree[k].lp = tree[2*k].lp;
            tree[k].rp = (tree[2*k].rp != tree[2*k+1].rp);
            tree[k].mp = tree[2*k].mp;
        }
    }

    bool range_has(ll l, ll r) { return range_has(1, 0, nt-1, l, r); }
    bool range_has(ll k, ll tl, ll tr, ll l, ll r) {
        prop(k);
        if (r < tl || l > tr) return false;
        if (l <= tl && r >= tr) return tree[k].has;
        ll mid = tl + (tr - tl) / 2;
        return range_has(2*k, tl, mid, l, r) || range_has(2*k+1, mid+1, tr, l, r);
    }

    void range_set(ll l, ll r) { return range_set(1, 0, nt-1, l, r); }
    void range_set(ll k, ll tl, ll tr, ll l, ll r) {
        prop(k);
        if (r < tl || l > tr) return;
        if (l <= tl && r >= tr) {
            tree[k].lazy = true;
            tree[k].lz_val = true;
            prop(k);
            return;
        }
        ll mid = tl + (tr - tl) / 2;
        range_set(2*k, tl, mid, l, r);
        range_set(2*k+1, mid+1, tr, l, r);
        recalc(k);
    }

    void range_unset(ll l, ll r) { return range_unset(1, 0, nt-1, l, r); }
    void range_unset(ll k, ll tl, ll tr, ll l, ll r) {
        prop(k);
        if (r < tl || l > tr) return;
        if (l <= tl && r >= tr) {
            tree[k].lazy = true;
            tree[k].lz_val = false;
            prop(k);
            return;
        }
        ll mid = tl + (tr - tl) / 2;
        range_unset(2*k, tl, mid, l, r);
        range_unset(2*k+1, mid+1, tr, l, r);
        recalc(k);
    }

    bool is_legal() {
        prop(1);
        return !tree[1].lp && !tree[1].rp && !tree[1].mp;
    }

    void bake(ll k) {
        prop(k);
        if (k >= nt) return;
        bake(2*k);
        bake(2*k+1);
    }
};

void solve() {
    ll n, _; cin >> n >> _;
    vector<P> pts(n);
    vector<ll> ys;
    for (auto &p : pts) cin >> p.x >> p.y, ys.push_back(p.y);
    sort(all(ys)); ys.erase(unique(all(ys)), ys.end());
    for (auto &[x, y] : pts) y = lower_bound(all(ys), y) - ys.begin();
    ll ly = 0;
    for (auto &y : ys) {
        ll d = y - ly;
        if (d == 0) continue;
        if (d & 1) d = 1;
        else d = 2;
        ly = y = ly + d;
    }
    for (auto &[x, y] : pts) y = ys[y];
    if (polygonArea2(pts) < 0) reverse(all(pts));

    vector<event> events;
    for (ll i = 0; i < n; i++) {
        ll j = (i + 1) % n;
        if (pts[i].y == pts[j].y) continue;
        if (pts[i].y > pts[j].y) { // start
            events.emplace_back(pts[i].x, pts[j].y, pts[i].y - 1, false);
        }
        else { // stop
            events.emplace_back(pts[i].x, pts[i].y, pts[j].y - 1, true);
        }
    }
    sort(all(events));

    ll res = 0;
    segtree even(ys.back() + 2), odd(ys.back() + 2);
    vector<bool> lx(sz(events));
    lx.back() = true;
    ll ppx = 0;
    for (ll i = 0; i+1 < sz(events); i++) lx[i] = (events[i].x != events[i+1].x);
    for (ll i = 0; i < sz(events); i++) {
        auto [x, l, r, stop] = events[i];
        segtree &t = ((x & 1) ? odd : even);
        segtree &o = ((x & 1) ? even : odd);

        if (ppx != x) {
            ppx = x;
            if (t.range_has(0, inf) == 0) res = max(res, x-1);
            if (o.range_has(0, inf) == 0) res = max(res, x);
        }

        if (!stop) {
            t.range_set(l, r);
        }
        else {
            if (o.range_has(l, r) > 0) break;
            t.range_unset(l, r);
        }

        if (lx[i]) {
            if (!t.is_legal() || !o.is_legal()) break;
        }
    }
    cout << res << '\n';
}

signed main() {
    cin.tie(0)->sync_with_stdio(0);
    solve();
}
#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...