BZOJ4311 向量(线段树分治+凸包)

BZOJ4311 向量(线段树分治+凸包)

题目大意

你要维护一个向量集合,支持以下操作:

  1. 插入一个向量 (x, y)

  2. 删除插入的第 i 个向量

  3. 查询当前集合与 (x, y) 点积的最大值是多少。如果当前是空集输出 0

数据范围

$ n \le 200000 , 1 \le x,y \le 10^6 $

解题思路

线段树分治好题

首先发现对于一个向量所在的直线,垂直于它的所有直线斜率相等,这样的直线经过向量集合中的点且最靠右的即为答案,不难发现维护向量集合的凸包即可

凸包不好合并更不好删除,考虑线段树分治,将每个向量出现的时间分为 $ log $ 段,挂在线段树上,并在线段树上每个点构建一个凸包,求解单个凸包时可以用三分,询问就是从根节点到叶节点所有答案的最小值

我的写法中提前将点按 x 排序,常数回小一点把,凸包是一个节点构建完就询问的

代码如下

#pragma GCC optimize(3, "inline")
#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Pa pair<ll, ll>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }

template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }

const int N = 300500;
int cnt, cnt2, T, tp;
struct node {
	ll x, y, l, r;
	bool operator < (const node &i) const {
		return x < i.x;
	}
}vec[N], v[N];

vector<Pa > poi[N<<2];
Pa st[N];

#define ls p << 1
#define rs ls | 1
void change(int p, int l, int r, Pa x, int L, int R) {
	if (L <= l && r <= R) return poi[p].push_back(x), void();
	int mid = (l + r) >> 1;
	if (L <= mid) change(ls, l, mid, x, L, R);
	if (mid < R)  change(rs, mid + 1, r, x, L, R); 
}

double K(Pa a, Pa b, Pa c) {
	return (a.se - b.se) * (a.fi - c.fi) < (a.se - c.se) * (a.fi - b.fi) ;
}

ll Ans(Pa a, Pa b) {
	return a.fi * b.fi + a.se * b.se;
}

ll ans[N];
void solve(int p, int l, int r) {
	tp = 0;
	for (auto x: poi[p]) {
		while (tp > 1 && K(st[tp-1], st[tp], x)) tp--;
		st[++tp] = x;
	}
	for (int i = l;i <= r; i++) {
		if (!v[i].l) continue;
		Pa t = MP(v[i].x, v[i].y);
		int L = 1, R = tp, ti = 0;
		while (L < R) {
			ti++;
			int m1 = (L + R) >> 1;
			if (Ans(t, st[m1]) < Ans(t, st[m1+1])) L = m1 + 1;
			else R = m1;
		}
		Mx(ans[v[i].l], Ans(t, st[R]));
	}
	if (l == r) return; int mid = (l + r) >> 1;
	solve(ls, l, mid), solve(rs, mid + 1, r);
}

int main() {
	freopen ("hs.in","r",stdin);
	freopen ("hs.out","w",stdout); 
	int n; read(n);
	for (int i = 1;i <= n; i++) {
		int op, x, y;
		read(op), read(x);
		if (op == 1)
			read(y), vec[++cnt] = (node) { x, y, i, n };
		else if (op == 2) vec[x].r = i;
		else read(y), cnt2++, v[i] = (node) {x, y, cnt2, cnt2};
	}
	
	sort(vec + 1, vec + cnt + 1);
	for (int i = 1;i <= cnt; i++) 
		change(1, 1, n, MP(vec[i].x, vec[i].y), vec[i].l, vec[i].r);
	
	solve(1, 1, n);
	for (int i = 1;i <= cnt2; i++) printf ("%lld\n", ans[i]);
	
	return 0;
}
posted @ 2020-04-22 23:52  Hs-black  阅读(193)  评论(0编辑  收藏  举报