CF678F Lena and Queries
阿新 • • 發佈:2021-12-17
https://www.luogu.com.cn/problem/CF678F
首先一眼線段樹分治
然後線段樹上每個節點建一個凸包,在上面三分即可
code:
#include<bits/stdc++.h> #define ll long long #define N 300050 using namespace std; const ll inf = 2e18; struct P { ll x, y; P operator + (const P o) {return (P){x + o.x, y + o.y}; } P operator - (const P o) {return (P){x - o.x, y - o.y}; } ll operator * (const P o) {return x * o.y - y * o.x; } bool operator < (const P o) const {return x == o.x? y < o.y : x < o.x; } } a[N], sta[N]; ll cross(P a, P b, P c) { return (b - a) * (c - a); } ll calc(P o, ll k) { //printf("%lld %lld %lld\n", o.x, o.y, k); return k * o.x + o.y; } struct TB { vector<P> v; void push(P x) {v.push_back(x);} void px() { sort(v.begin(), v.end()); //printf("%d\n", v.size()); //for(auto x : v) printf("(%lld %lld) ", x.x, x.y); printf("\n"); int top = 0; for(auto x : v) { while(top > 1 && cross(sta[top - 1], sta[top], x) >= 0) top --; sta[++ top] = x; } v.clear(); for(int i = 1; i <= top; i ++) v.push_back(sta[i]); //printf("** %d\n", top); } ll query(ll k) { if(!v.size()) return - inf; int l = 0, r = v.size() - 1; while(l + 1 < r) { int mid = (l + r) >> 1; if(calc(v[mid], k) < calc(v[mid + 1], k)) l = mid; else r = mid; } // printf("%lld (%lld %lld) %lld \n", k, v[0].x, v[0].y, calc(v[0], k)); return max(calc(v[l], k), calc(v[r], k)); } } V[N << 3]; #define ls (rt << 1) #define rs (rt << 1 | 1) void insert(int rt, int l, int r, int L, int R, P o) { if(L <= l && r <= R) { // printf("** %d %d %d\n", l, r, o.x); V[rt].push(o); return ; } int mid = (l + r) >> 1; if(L <= mid) insert(ls, l, mid, L, R, o); if(R > mid) insert(rs, mid + 1, r, L, R, o); } void build(int rt, int l, int r) { V[rt].px(); if(l == r) return ; int mid = (l + r) >> 1; build(ls, l, mid), build(rs, mid + 1, r); } ll query(int rt, int l, int r, int x, ll k) { ll ret = V[rt].query(k); //printf(" %d %d %d %d %lld %d\n", l, r, L, R, k, (int)V[rt].v.size()); if(l == r) return ret; int mid = (l + r) >> 1; if(x <= mid) ret = max(ret, query(ls, l, mid, x, k)); else ret = max(ret, query(rs, mid + 1, r, x, k)); return ret; } int n, o[N], R[N], k[N]; int main() { scanf("%d", &n); for(int i = 1; i <= n; i ++) { int x; scanf("%d", &o[i]); if(o[i] == 1) { scanf("%lld%lld", &a[i].x, &a[i].y); R[i] = n; } if(o[i] == 2) { scanf("%d", &x); R[x] = i; } if(o[i] == 3) { scanf("%d", &k[i]); } } for(int i = 1; i <= n; i ++) if(R[i]) { insert(1, 1, n, i, R[i], a[i]); } build(1, 1, n); for(int i = 1; i <= n; i ++) if(o[i] == 3) { ll ret = query(1, 1, n, i, k[i]); if(ret == -inf) printf("EMPTY SET\n"); else printf("%lld\n", ret); } return 0; }