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;
}