题解:P17741 [ICPC 2019 Xuzhou R] K-rectangle
最后两分钟场切了,应当为我颁发顽强拼搏奖。
首先所有点按照
注意到矩形的底边都在
拆开来看看:
又有
首先设
所以对于每一段里面,只需要维护下面式子的最大值:
假设某一个段里的最大
外部再用一个李超树维护所有段的信息即可。
注意到我们
注意到当我们插入一个新的段时,他可能和前面若干段合并,为了合并后能快速求出这一段内的最优决策,需要每一段上维护李超树,合并段的时候做李超树合并。
总而言之复杂度为
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 4e5 + 10;
const int M = N * 30;
const int V = 1e6;
const int inf = 1e18;
int n, k, f[N], top, stk[N], rec[N];
struct node { int x, y; } p[N];
struct seg { int l, r, v, u; } w[N];
struct LCT1 {
int k[N], b[N], rt[N], cnt;
int mx[M], lc[M], rc[M];
int val(int id, int x) {
return k[id] * x + b[id];
}
void upd(int &p, int l, int r, int x) {
if (!p) p = ++cnt;
if (!mx[p]) {mx[p] = x; return;}
int mid = (l + r) >> 1;
if (val(mx[p], mid) > val(x, mid)) swap(mx[p], x);
if (val(mx[p], l) > val(x, l)) upd(lc[p], l, mid, x);
if (val(mx[p], r) > val(x, r)) upd(rc[p], mid + 1, r, x);
return;
}
int ask(int p, int l, int r, int x) {
if (!p) return inf;
int tmp = val(mx[p], x), mid = (l + r) >> 1;
if (l == r) return tmp;
if (x <= mid) tmp = min(tmp, ask(lc[p], l, mid, x));
if (x > mid) tmp = min(tmp, ask(rc[p], mid + 1, r, x));
return tmp;
}
int unite(int p, int q, int l, int r) {
if (!p || !q) return p + q;
if (mx[q]) upd(p, l, r, mx[q]);
if (l == r) return p;
int mid = (l + r) >> 1;
lc[p] = unite(lc[p], lc[q], l, mid);
rc[p] = unite(rc[p], rc[q], mid + 1, r);
return p;
}
void merge(int p, int q) {
rt[p] = unite(rt[p], rt[q], 1, V);
}
void ins(int id, int _k, int _b) {
k[id] = _k, b[id] = _b;
upd(rt[id], 1, V, id);
}
int qry(int id, int x) {
return ask(rt[id], 1, V, x);
}
} T;
struct LCT2 {
int top, *pos[M], vaw[M];
int k[N], b[N], rt, cnt;
int lc[M], rc[M], mx[M];
void push(int &x) {
++top, pos[top] = &x, vaw[top] = x;
return;
}
void pop() {
*pos[top] = vaw[top];
return;
}
int val(int id, int x) {
return k[id] * x + b[id];
}
void upd(int &p, int l, int r, int x) {
if (!p) push(p), p = ++cnt;
if (!mx[p]) {push(mx[p]), mx[p] = x; return;}
int mid = (l + r) >> 1;
if (val(mx[p], mid) > val(x, mid)) {
push(mx[p]);
swap(mx[p], x);
}
if (val(mx[p], l) > val(x, l)) upd(lc[p], l, mid, x);
if (val(mx[p], r) > val(x, r)) upd(rc[p], mid + 1, r, x);
return;
}
void ins(int id, int _k, int _b) {
k[id] = _k, b[id] = _b;
upd(rt, -V, V, id);
}
int ask(int p, int l, int r, int x) {
if (!p) return inf;
int tmp = val(mx[p], x), mid = (l + r) >> 1;
if (l == r) return tmp;
if (x <= mid) tmp = min(tmp, ask(lc[p], l, mid, x));
if (x > mid) tmp = min(tmp, ask(rc[p], mid + 1, r, x));
return tmp;
}
int qry(int x) {
return ask(rt, -V, V, x);
}
void pop(int rec) {
while (top > rec) pop(), top--;
}
} tr;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> p[i].x >> p[i].y;
}
sort(p + 1, p + 1 + n, [&](node u, node v) {
return u.x == v.x ? u.y < v.y : u.x < v.x;
});
int _n = n; n = 0; p[0].x = -1e9;
for (int i = 1; i <= _n; i++) {
if (p[i].x == p[n].x) {
p[n] = p[i];
} else {
p[++n] = p[i];
}
}
for (int i = 1; i <= n; i++) {
T.ins(i, -p[i].x, f[i - 1]);
while (top && p[i].y > p[stk[top]].y) {
T.merge(i, stk[top]);
tr.pop(rec[stk[top]]);
top -= 1;
}
rec[i] = tr.top; stk[++top] = i;
tr.ins(i, p[i].y, T.qry(i, p[i].y) + p[i].y * k);
f[i] = tr.qry(p[i].x);
}
cout << f[n] << '\n';
return 0;
}
如有错误,请指出。