ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【ybt金牌导航6-1-2】向量问题

2021-07-03 08:00:38  阅读:204  来源: 互联网

标签:return xl int ybt 1ll now 金牌 向量


向量问题

题目链接:ybt金牌导航6-1-2

题目大意

要你支持一些操作:
加一个向量,删除第 i 个向量,给一个向量问当前有的哪个向量与它的点积最大。
如果是当前没有向量输出 0,否则输出这个最大点积。

思路

先看操作 \(3\),设给出询问的向量是 \(a,b\),你要找到一组原有的 \(x,y\),使得 \(ax+by\) 最大。
那设这个最大值是 \(c\),那就有 \(c=ax+by\),移项搞搞什么的就得到了:\(y=-a/b*x+c/b\)
容易看到当 \(c\) 最大时,这个直线的截距就最大。那向量都是在第一象限,所以答案一定是在上凸包上。
那我们可以考虑在上凸壳上二分或者搞什么决策单调化什么的。

但还有一个问题,它有插入删除操作。
那就是说,它向量它只会在一个时间段里出现。
那我们考虑以时间为下标建线段树,然后插入就区间插入,到时查询就跑查询到它这个时间的链,然后链中的每个点的凸包都求一次最大值,然后把这些最大值再取最大值。
而这个线段树以时间为下标,它就是线段树分治。

那你在上凸壳上二分一个 \(log\),线段树一个 \(log\),复杂度就是 \(O(nlog^2n)\)

当然我们还可以继续优化,就是把二分换成决策单调化。
我们考虑以一个顺序处理询问,使得它的答案按 \(x\) 坐标单调不减,那我们的最右决策点只要不停右移就能找到。
不难想到我们把询问按 \(-a/b\) 从大到小排即可。

代码

#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
#define ll long long

using namespace std;

struct xl {
	int x, y;
};
struct rd {
	int l, r;
	xl p;
}a[200001], b[200001], c[200001];
int n, op, num[200001], x, qn, wn, pl[800001];
ll ans[200001];
vector <xl> v[800001];

xl operator -(xl x, xl y) {//向量减法
	return (xl){x.x - y.x, x.y - y.y};
}

ll dot(xl x, xl y) {//点积
	return 1ll * x.x * y.x + 1ll * x.y * y.y;
}

ll cross(xl x, xl y) {//叉积
	return 1ll * x.x * y.y - 1ll * x.y * y.x;
}

bool cmp1(rd x, rd y) {//按 x 排序
	if (x.p.x != y.p.x) return x.p.x < y.p.x;
	return x.p.y < y.p.y;
}

bool cmp2(rd x, rd y) {//按 -a/b 从大到小排,使得最优决策点按 x 坐标单调不降
	return 1ll * x.p.x * y.p.y < 1ll * y.p.x * x.p.y;
}

//线段树操作
void insert(int now, int l, int r, int L, int R, xl &p) {
	if (L <= l && r <= R) {
		while (v[now].size() >= 2 && cross(p - v[now][v[now].size() - 1], p - v[now][v[now].size() - 2]) <= 0)
			v[now].pop_back();//维护上凸包
		v[now].push_back(p);
		return ;
	}
	int mid = (l + r) >> 1;
	if (L <= mid) insert(now << 1, l, mid, L, R, p);
	if (mid < R) insert(now << 1 | 1, mid + 1, r, L, R, p);
}

ll query(int now, int l, int r, int pla, xl &p) {
	ll ans = 0;
	if (v[now].size()) {//在路上的每个集合都要找上凸包
		while (pl[now] < v[now].size() - 1 && dot(p, v[now][pl[now] + 1]) >= dot(p, v[now][pl[now]]))
			pl[now]++;
		ans = dot(p, v[now][pl[now]]);
	}
	if (l == r) return ans;
	
	int mid = (l + r) >> 1;
	if (pla <= mid) return max(ans, query(now << 1, l, mid, pla, p));//然后取最大值
		else return max(ans, query(now << 1 | 1, mid + 1, r, pla, p));
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &op);
		if (op == 1) {
			scanf("%d %d", &a[i].p.x, &a[i].p.y);
			a[i].l = i; a[i].r = n;
			num[++num[0]] = i;
			continue;
		}
		if (op == 2) {
			scanf("%d", &x);
			a[num[x]].r = i - 1;
			a[i].r = -114514;//只是标记,到时好区分操作二操作三
			continue;
		}
		if (op == 3) {
			qn++;
			scanf("%d %d", &c[qn].p.x, &c[qn].p.y);
			c[qn].l = i;
			continue;
		}
	}
	
	for (int i = 1; i <= n; i++)
		if (a[i].l) b[++wn] = a[i];
	sort(b + 1, b + wn + 1, cmp1);
	for (int i = 1; i <= wn; i++)
		insert(1, 1, n, b[i].l, b[i].r, b[i].p);
	
	for (int i = 1; i <= qn; i++)
		ans[c[i].l] = query(1, 1, n, c[i].l, c[i].p);
	
	for (int i = 1; i <= n; i++)
		if (!a[i].r) printf("%lld\n", ans[i]);
	
	return 0;
}

标签:return,xl,int,ybt,1ll,now,金牌,向量
来源: https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_6-1-2.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有