题目大意
两个操作:
1.在序列S中加入一个向量;
2.求某个向量和S的区间
中向量的点积最大值。
题解
考虑两个向量
,询问向量为
。不妨令
,如果1比2优,则有
。若
,则
。因此我们应该维护一个斜率递减的凸包(即上凸包)。
同理对于
的情况我们需要维护一个下凸包,这个可以把所有坐标取相反数维护一个上凸包。
于是在往后加入点的过程中,如果线段树某个节点满了,就重建凸包,坐标排序那部分可以直接归并排序解决,复杂度就是
的了。
对于询问,我们需要在每个节点上的凸包中二分斜率,因此这部分的复杂度为
。
#include <bits/stdc++.h>
using namespace std;
const int MAXR = 10000000;
char _READ_[MAXR], _PRINT_[MAXR];
int _READ_POS_, _PRINT_POS_, _READ_LEN_;
inline char readc() {
#ifndef ONLINE_JUDGE
return getchar();
#endif
if (!_READ_POS_) _READ_LEN_ = fread(_READ_, 1, MAXR, stdin);
char c = _READ_[_READ_POS_++];
if (_READ_POS_ == MAXR) _READ_POS_ = 0;
if (_READ_POS_ > _READ_LEN_) return 0;
return c;
}
template<typename T> inline void read(T &x) {
x = 0; register int flag = 1, c;
while (((c = readc()) < '0' || c > '9') && c != '-');
if (c == '-') flag = -1; else x = c - '0';
while ((c = readc()) >= '0' && c <= '9') x = x * 10 + c - '0';
x *= flag;
}
template<typename T1, typename ...T2> inline void read(T1 &a, T2&... x) {
read(a), read(x...);
}
inline int reads(char *s) {
register int len = 0, c;
while (isspace(c = readc()) || !c);
s[len++] = c;
while (!isspace(c = readc()) && c) s[len++] = c;
s[len] = 0;
return len;
}
inline void ioflush() { fwrite(_PRINT_, 1, _PRINT_POS_, stdout), _PRINT_POS_ = 0; fflush(stdout); }
inline void printc(char c) {
_PRINT_[_PRINT_POS_++] = c;
if (_PRINT_POS_ == MAXR) ioflush();
}
inline void prints(char *s) {
for (int i = 0; s[i]; i++) printc(s[i]);
}
template<typename T> inline void print(T x, char c = '\n') {
if (x < 0) printc('-'), x = -x;
if (x) {
static char sta[20];
register int tp = 0;
for (; x; x /= 10) sta[tp++] = x % 10 + '0';
while (tp > 0) printc(sta[--tp]);
} else printc('0');
printc(c);
}
template<typename T1, typename ...T2> inline void print(T1 x, T2... y) {
print(x, ' '), print(y...);
}
typedef long long ll;
const int MAXT = 1 << 20 | 5, MAXN = 400005;
struct Vec {
int x, y;
inline Vec operator-(const Vec &v) const { return (Vec) { x - v.x, y - v.y }; }
inline Vec operator-() const { return (Vec) { -x, -y }; }
inline ll det(const Vec &v) const { return (ll)x * v.y - (ll)y * v.x; }
inline ll dot(const Vec &v) const { return (ll)x * v.x + (ll)y * v.y; }
inline bool operator<(const Vec &v) const { return x == v.x ? y < v.y : x < v.x; }
} temp[MAXN];
struct Hull {
Vec *po; int n;
inline Vec& operator[](int x) { return po[x]; }
inline const Vec& operator[](int x) const { return po[x]; }
void merge(const Hull &a, const Hull &b) {
int ha = 0, hb = 0; n = 0;
while (ha < a.n || hb < b.n) {
Vec now = ha < a.n && (hb == b.n || a[ha] < b[hb]) ? a[ha++] : b[hb++];
while (n > 1 && (temp[n - 1] - temp[n - 2]).det(now - temp[n - 1]) >= 0) --n;
temp[n++] = now;
}
po = new Vec[n];
for (int i = 0; i < n; i++) po[i] = temp[i];
}
ll query(const Vec &v) {
int l = -1, r = n - 1;
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (po[mid].dot(v) >= po[mid + 1].dot(v)) r = mid;
else l = mid;
}
return po[r].dot(v);
}
} tr[MAXT][2];
int tot, n, tn;
void push(const Vec &v) {
int k = (++tot) + tn - 1;
tr[k][0].po = new Vec[1] { v };
tr[k][1].po = new Vec[1] { -v };
tr[k][0].n = tr[k][1].n = 1;
while ((k & 1) && k > 0) {
k >>= 1;
tr[k][0].merge(tr[k << 1][0], tr[k << 1 | 1][0]);
tr[k][1].merge(tr[k << 1][1], tr[k << 1 | 1][1]);
}
}
ll query(int a, int b, const Vec &v, int l = 1, int r = tn, int k = 1) {
if (a > r || b < l) return LLONG_MIN;
if (a <= l && b >= r) return v.y < 0 ? tr[k][1].query(-v) : tr[k][0].query(v);
int mid = (l + r) >> 1;
return max(query(a, b, v, l, mid, k << 1), query(a, b, v, mid + 1, r, k << 1 | 1));
}
char opt[5], tp[5];
int main() {
read(n), reads(tp);
for (tn = 1; tn < n; tn <<= 1);
ll lst = 0;
while (n--) {
reads(opt); lst &= 0x7FFFFFFF;
if (opt[0] == 'Q') {
int x, y, l, r; read(x, y, l, r);
if (tp[0] != 'E') x ^= lst, y ^= lst, l ^= lst, r ^= lst;
print(lst = query(l, r, (Vec) { x, y }));
} else {
int x, y; read(x, y);
if (tp[0] != 'E') x ^= lst, y ^= lst;
push((Vec) { x, y });
}
}
ioflush();
return 0;
}