제출 #891229

#제출 시각아이디문제언어결과실행 시간메모리
891229ZaniteBulldozer (JOI17_bulldozer)C++17
100 / 100
996 ms81076 KiB
// When we're in drama,
// there's that person over there
// polishing their skill.

// 抗えぬ運命と決まっているのなら
// 私はあなたの為に生きたい
// 誰かの為に生きてこその人生
// 輝を増すこと知っているから

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

// Pragmas
// #pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

// Namespaces
using namespace std;
using namespace __gnu_pbds;

// Data types
using si  = short int;
using ll  = long long;
using ull = unsigned long long;
using lll = __int128;
using ld  = long double;

// Pairs
using pii  = pair<int, int>;
using psi  = pair<si, si>;
using pll  = pair<ll, ll>;
using plll = pair<lll, lll>;
using pld  = pair<ld, ld>;
#define fi first
#define se second

// PBDS
template<typename Z>
using ordered_set = tree<Z, null_type, less<Z>, rb_tree_tag, tree_order_statistics_node_update>;

// Various outputs
template<typename Y, typename Z>
ostream& operator<<(ostream &os, const pair<Y, Z> &p) {
    return os << "(" << p.fi << ", " << p.se << ")";
}
template<typename RZ>
ostream& operator<<(ostream &os, const tuple<RZ, RZ> &r) {
    os << "{"; bool _first = 1;
    for (RZ i = get<0>(r); i != get<1>(r); i++) {
        if (!_first) os << ", ";
        os << *i; _first = 0;
    }
    return os << "}";
}
template<typename Z>
ostream& operator<<(ostream &os, const vector<Z> &v) {
    return os << make_tuple(v.begin(), v.end());
}

// Quick macro functions
#define sqr(x)        ((x)*(x))
#define debug(x)      cout << #x << " = " << (x) << '\n'
#define debugV(v, x)  cout << #v << "[" << (x) << "] = " << (v[x]) << '\n'
#define rrebug(x)     cerr << #x << " = " << (x) << '\n'
#define rrebugV(v, x) cerr << #v << "[" << (x) << "] = " << (v[x]) << '\n'

#define All(x)       x.begin(), x.end()
#define Sort(x)      sort(All(x))
#define Reverse(x)   reverse(All(x))
#define Uniqueify(x) Sort(x); x.erase(unique(All(x)), x.end())

#define RandomSeed        chrono::steady_clock::now().time_since_epoch().count()
#define MultipleTestcases int _tc; cin >> _tc; for (int _cur_tc = 1; _cur_tc <= _tc; _cur_tc++)

// Check min and max
template<typename Z> bool chmin(Z &a, Z b) {return (b < a) ? a = b, true : false;}
template<typename Z> bool chmax(Z &a, Z b) {return (b > a) ? a = b, true : false;}
 
// Modular arithmetic
template<int MOD>
class ModInt {
  public:
    int v;
    ModInt() : v(0) {}
    ModInt(long long _v) {
        v = int((-MOD < _v && _v < MOD) ? (_v) : (_v % MOD));
        if (v < 0) v += MOD;
    }
 
    friend bool operator==(const ModInt &a, const ModInt &b) {return a.v == b.v;}
    friend bool operator!=(const ModInt &a, const ModInt &b) {return a.v != b.v;}
    friend bool operator< (const ModInt &a, const ModInt &b) {return a.v <  b.v;}
    friend bool operator<=(const ModInt &a, const ModInt &b) {return a.v <= b.v;}
    friend bool operator> (const ModInt &a, const ModInt &b) {return a.v >  b.v;}
    friend bool operator>=(const ModInt &a, const ModInt &b) {return a.v >= b.v;}
 
    ModInt &operator+=(const ModInt &a) {if ((v += a.v) >= MOD) v -= MOD; return *this;}
    ModInt &operator-=(const ModInt &a) {if ((v -= a.v) < 0) v += MOD; return *this;}
    ModInt &operator*=(const ModInt &a) {v = 1ll * v * a.v % MOD; return *this;}
    ModInt &operator/=(const ModInt &a) {return (*this) *= inverse(a);}
 
    friend ModInt pow(ModInt a, long long x) {
        ModInt res = 1;
        for (; x; x /= 2, a *= a) if (x & 1) res *= a;
        return res;
    }
    friend ModInt inverse(ModInt a) {return pow(a, MOD - 2);}
 
    ModInt operator+ () const {return ModInt( v);}
    ModInt operator- () const {return ModInt(-v);}
    ModInt operator++() const {return *this += 1;}
    ModInt operator--() const {return *this -= 1;}
 
    friend ModInt operator+(ModInt a, const ModInt &b) {return a += b;}
    friend ModInt operator-(ModInt a, const ModInt &b) {return a -= b;}
    friend ModInt operator*(ModInt a, const ModInt &b) {return a *= b;}
    friend ModInt operator/(ModInt a, const ModInt &b) {return a /= b;}
 
    friend istream &operator>>(istream &is, ModInt &v) {return is >> v.v;}
    friend ostream &operator<<(ostream &os, const ModInt &v) {return os << v.v;}
};
const int ModA = 998244353;
const int ModC = 1e9 + 7;
using MintA    = ModInt<ModA>;
using MintC    = ModInt<ModC>;

// Other constants
const ll INF  = 1e18;
const ll iINF = 1e9;
const ld EPS  = 1e-9;
const ld iEPS = 1e-6;

template<typename Z>
bool geomAbs(Z x) {
    if (x < EPS) return x;
    return x;
}
template<typename Z>
bool geomBetween(Z x, Z l, Z r) {
    // l <= x <= r
    if (l > r) swap(l, r);
    return (l <= x + EPS) && (x <= r + EPS);
}
template<typename Z>
bool geomEqual(Z a, Z b) {
    return geomBetween(a, b, b);
}

// Point

template<typename Z>
struct Point {
    Z x, y;
    
    Point(Z x = 0, Z y = 0) :
        x(x), y(y)
    {}

    bool operator<(const Point<Z> &other) const {
        if (x < other.x + EPS) return true;
        if (x + EPS > other.x) return false;
        return y < other.y + EPS;
    }
    bool operator==(const Point &other) const {
        return geomEqual(x, other.x) && geomEqual(y, other.y);
    }

    friend istream& operator>>(istream &is, Point<Z> &P) {
        return is >> P.x >> P.y;
    }
};

template<typename Z>
struct Line {
    Z a, b, c;

    Line(Z a = 0, Z b = 0, Z c = 0) :
        a(a), b(b), c(c)
    {}
    Line(Point<Z> P1, Point<Z> P2) {
        if (P1 < P2) swap(P1, P2);
        if (geomEqual(P1.x, P2.x)) {
            a = 1;
            b = 0;
            c = -P1.x;
        } else {
            a = -(P1.y - P2.y) / (P1.x - P2.x);
            b = 1;
            c = -(a * P1.x) - P1.y;
        }
    }
    Line(Point<Z> P, Z slope) {
        a = -slope;
        b = 1;
        c = -(a * P.x) - P.y;
    }

    bool operator==(const Line &other) const {
        return geomEqual(a, other.a) && geomEqual(b, other.b) && geomEqual(c, other.c);
    }

    ld slope() {
        return -((ld)a / (ld)b);
    }
};

struct Segtree {
    struct Elm {
        ll pf, sf, mx, sum;
        Elm() {
            pf = sf = mx = -INF;
            sum = 0;
        }
        Elm(ll val) {
            pf = sf = mx = max(val, 0ll);
            sum = val;
        }
    };
	Elm DEFAULT = Elm();

	#define m	((l+r) >> 1)
	#define lc	(pos << 1)
	#define rc	(lc | 1)

	int sz;
	vector<Elm> seg;

	Segtree(int sz) : sz(sz) {seg.assign((sz << 2) + 1, DEFAULT);}

	void updateNode(int pos, ll val) {
		seg[pos] = Elm(val);
	}

	Elm merge(Elm a, Elm b) {
		Elm nw = Elm();
        nw.pf = max({-INF, a.pf, a.sum + b.pf});
        nw.sf = max({-INF, b.sf, b.sum + a.sf});
        nw.mx = max({-INF, a.mx, b.mx, a.sf + b.pf});
        nw.sum = a.sum + b.sum;
        return nw;
	}

	void update(int pos, int l, int r, int idx, ll val) {
		if (l == r) {
			updateNode(pos, val);
			return;
		}

		if (idx <= m) {update(lc, l, m, idx, val);}
		else {update(rc, m+1, r, idx, val);}
		seg[pos] = merge(seg[lc], seg[rc]);
	}
	void update(int idx, ll val) {update(1, 1, sz, idx, val);}

	Elm query(int pos, int l, int r, int ql, int qr) {
		if (l > r || ql > qr || ql > r || l > qr) {return DEFAULT;}
		if (ql <= l && r <= qr) {return seg[pos];}

		return merge(query(lc, l, m, ql, qr), query(rc, m+1, r, ql, qr));
	}
	Elm query(int ql, int qr) {return query(1, 1, sz, ql, qr);}

	#undef	m
	#undef	lc
	#undef	rc
};

bool _less(ld x, ld y) {return x - y < -EPS;}
bool _greater(ld x, ld y) {return x - y > EPS;}

using TempPoint = tuple<ll, ll, ll>; // {x, y, w}
const ld ld_infinity = (ld)1 / (ld)0;

const int maxN  = 2'023;

int N;
TempPoint TP[maxN];
pll P[maxN];
ll W[maxN];
ld C[maxN][maxN];
vector<pii> pairs;
int pos[maxN];

ld getLineC(pll a, pll b) {
    if (a.fi == b.fi) {
        return -a.fi;
    } else {
        ld d = -(ld)(a.se - b.se) / (ld)(a.fi - b.fi);
        ld c = -d * (ld)(a.fi) - (ld)a.se;
        return c;
    }
}

int compareSlope(pii a, pii b) {
    pll A1 = P[a.fi], A2 = P[a.se];
    pll B1 = P[b.fi], B2 = P[b.se];

    bool a_inf = (A1.fi == A2.fi);
    bool b_inf = (B1.fi == B2.fi);
    if (a_inf && b_inf) return 0;
    if (a_inf) return -1;
    if (b_inf) return 1;

    //    (A2.y - A1.y) / (A1.x - A2.x) - (B2.y - B1.y) / (B1.x - B2.x)
    // -> (A2.y - A1.y)(B1.x - B2.x) - (B2.y - B1.y)(A1.x - A2.x)

    ll cur = (A2.se - A1.se) * (B1.fi - B2.fi) - (B2.se - B1.se) * (A1.fi - A2.fi);
    if (cur < 0) return -1;
    if (cur > 0) return 1;
    return 0;
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(NULL);
    
    cin >> N;
    for (int i = 1; i <= N; i++) {
        auto &[x, y, w] = TP[i];
        cin >> x >> y >> w;
    }

    sort(TP + 1, TP + N + 1);
    for (int i = 1; i <= N; i++) {
        auto &[x, y, w] = TP[i];
        P[i] = {x, y};
        W[i] = w;
    }

    for (int i = 1; i <= N; i++) {
        for (int j = i; j <= N; j++) {
            C[i][j] = getLineC(P[i], P[j]);
            pairs.push_back({i, j});
        }
    }

    sort(All(pairs), [&](const pii &a, const pii &b){
        auto &[ai, aj] = a;
        auto &[bi, bj] = b;

        int cs = compareSlope(a, b);
        if (cs == -1) return true;
        if (cs == 1) return false;

        if (_less(C[ai][aj], C[bi][bj])) return true;
        if (_greater(C[ai][aj], C[bi][bj])) return false;

        if (ai < bi) return true;
        if (ai > bi) return false;
        return aj < bj;
    });

    Segtree S(N);
    for (int i = 1; i <= N; i++) {
        pos[i] = i;
        S.update(i, W[i]);
    }
    ll ans = S.query(1, N).mx;
    int P = pairs.size();

    for (int i = 0; i < P; i++) {
        auto &[ci, cj] = pairs[i];
        swap(pos[ci], pos[cj]);
        S.update(pos[ci], W[ci]);
        S.update(pos[cj], W[cj]);

        bool process = true;
        if (i < P-1) {
            if (compareSlope(pairs[i], pairs[i+1]) != -1) {
                process = false;
            }
        }

        if (process) {
            chmax(ans, S.query(1, N).mx);
        }
    }

    cout << ans << "\n";
}

// あなたの傍に居させて...

// dibisakan
#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...