SDOI2014 向量集(凸包+线段树)

题目链接

题目大意

两个操作:
1.在序列S中加入一个向量;
2.求某个向量和S的区间 [ l , r ] [l,r] 中向量的点积最大值。
n , m 1 0 5 n,m\le 10^5

题解

考虑两个向量 ( a 1 , b 1 ) , ( a 2 , b 2 ) (a_1,b_1),(a_2,b_2) ,询问向量为 ( x , y ) (x,y) 。不妨令 a 1 a 2 a_1\le a_2 ,如果1比2优,则有 ( a 1 a 2 ) x ( b 2 b 1 ) y (a_1-a_2)x\ge (b_2-b_1)y 。若 y > 0 y>0 ,则 x / y ( b 1 b 2 ) / ( a 1 a 2 ) -x/y\ge (b_1-b_2)/(a_1-a_2) 。因此我们应该维护一个斜率递减的凸包(即上凸包)。
同理对于 y < 0 y<0 的情况我们需要维护一个下凸包,这个可以把所有坐标取相反数维护一个上凸包。
于是在往后加入点的过程中,如果线段树某个节点满了,就重建凸包,坐标排序那部分可以直接归并排序解决,复杂度就是 O ( n l o g n ) O(nlogn) 的了。
对于询问,我们需要在每个节点上的凸包中二分斜率,因此这部分的复杂度为 O ( n l o g 2 n ) O(nlog^2n)

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

猜你喜欢

转载自blog.csdn.net/WAautomaton/article/details/87107323