答案一定是在凸壳上的(y>0上凸壳, y<0下凸壳). 线段树维护, 至多N次询问, 每次询问影响O(logN)数量级的线段树结点, 每个结点O(logN)暴力建凸壳, 然后O(logN)三分(二分也是可以的, 不过三分好写, 而且没精度问题....), O(Nlog^2N), 可以AC。
--------------------------------------------------------------------------------------------
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define Decode(x) (x ^= (ans & 0X7FFFFFFF))
const int maxn = 400009;
bool Online;
int n, N, L, R, pos;
ll ans;
inline void Max(ll &x, ll t) {
if(t > x) x = t;
}
inline int getint() {
char c = getchar();
int ret = 0, f = 1;
for(; !isdigit(c); c = getchar())
if(c == '-') f = 0;
for(; isdigit(c); c = getchar())
ret = ret * 10 + c - '0';
return f ? ret : -ret;
}
struct P {
int x, y;
bool operator < (const P &o) const {
return x < o.x;
}
ll operator * (const P &o) const {
return ll(x) * o.x + ll(y) * o.y;
}
} p[maxn], o[maxn], seq[4000000], q;
struct Node {
Node *lc, *rc;
int l[2], r[2], t;
} pool[maxn << 1], *pt = pool, *Root;
void Build(Node* t, int l, int r) {
t->t = 0;
if(l != r) {
int m = (l + r) >> 1;
Build(t->lc = pt++, l, m);
Build(t->rc = pt++, m + 1, r);
}
}
inline bool chk(P &a, P &b, P &c, int t) {
int e = a.y - b.y, f = a.x - b.x, g = b.y - c.y, h = b.x - c.x;
if(h < 0) t ^= 1;
if(f < 0) t ^= 1;
return t ? ll(e) * h >= ll(f) * g : ll(e) * h <= ll(f) * g;
}
void ConvexHull(Node* t, int l, int r, int v) {
int len = 0, &Left = t->l[v];
for(int i = l; i <= r; i++) o[len++] = p[i];
sort(o, o + len);
seq[Left = pos] = o[0];
for(int i = 1; i < len; i++) {
if(seq[pos].x == o[i].x) {
if(!v && seq[pos].y >= o[i].y) continue;
if(v && seq[pos].y <= o[i].y) continue;
pos--;
}
while(pos > Left && chk(seq[pos - 1], seq[pos], o[i], v))
pos--;
seq[++pos] = o[i];
}
t->r[v] = pos++;
}
void Query(Node* t, int l, int r) {
if(L <= l && r <= R) {
if(!t->t) {
ConvexHull(t, l, r, 0);
ConvexHull(t, l, r, 1);
t->t = 1;
}
int Left = t->l[q.y < 0], Right = t->r[q.y < 0];
if(!q.y) {
Max(ans, max(seq[Left] * q, seq[Right] * q));
return;
}
while(Left <= Right) {
int d = (Right - Left) / 3, m1 = Left + d, m2 = Right - d;
Max(ans, max(seq[m1] * q, seq[m2] * q));
if(seq[m1] * q < seq[m2] * q) {
Left = m1 + 1;
} else
Right = m2 - 1;
}
} else {
int m = (l + r) >> 1;
if(L <= m) Query(t->lc, l, m);
if(m < R) Query(t->rc, m + 1, r);
}
}
void Init() {
N = getint();
char c;
scanf(" %c", &c);
Online = (c != 'E');
Build(Root = pt++, 1, N);
}
void Work() {
char c;
n = pos = 0, ans = 0;
for(int i = 0; i < N; i++) {
scanf(" %c", &c);
if(c != 'A') {
q.x = getint(), q.y = getint();
L = getint(), R = getint();
if(Online) {
Decode(q.x), Decode(q.y);
Decode(L), Decode(R);
}
ans = -1LL << 60;
Query(Root, 1, N);
printf("%lld\n", ans);
} else {
++n;
p[n].x = getint(), p[n].y = getint();
if(Online)
Decode(p[n].x), Decode(p[n].y);
}
}
}
int main() {
Init();
Work();
return 0;
}
--------------------------------------------------------------------------------------------
3533: [Sdoi2014]向量集
Time Limit: 25 Sec
Memory Limit: 512 MB
Submit: 495
Solved: 164
[ Submit][ Status][ Discuss]
Description
维护一个向量集合,在线支持以下操作:
"A x y (|x|,|y| < =10^8)":加入向量(x,y);
" Q x y l r (|x|,|y| < =10^8,1 < =L < =R < =T,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。
集合初始时为空。
Input
输入的第一行包含整数N和字符s,分别表示操作数和数据类别;
接下来N行,每行一个操作,格式如上所述。
请注意s≠'E'时,输入中的所有整数都经过了加密。你可以使用以下程序
得到原始输入:
inline int decode (int x long long lastans) {
return x ^ (lastans & Ox7fffffff);
}
function decode
begin
其中x为程序读入的数,lastans为之前最后一次询问的答案。在第一次询问之前,lastans=0。
注:向量(x,y)和(z,W)的点积定义为xz+yw。
Output
Sample Input
6 A
A 3 2
Q 1 5 1 1
A 15 14
A 12 9
Q 12 8 12 15
Q 21 18 19 18
Sample Output
13
17
17
解释:解密之后的输入为
6 E
A 3 2
Q 1 5 1 1
A 2 3
A 1 4
Q 1 5 1 2
Q 4 3 2 3
HINT
1 < =N < =4×10^5
新加数据一组..2015.315
Source