动态凸包

动态凸包

是什么

  动态凸包就是在可增删直线的情况下,求凸包(或凸包上的点)。

怎么求
  1. 离线所有操作
  2. 记录每一条直线出现和消失的时间
  3. 按照时间线建立线段树
  4. 在线段树上对应节点上插入直线(vector存储)
  5. 统一处理所有询问,即在每一个节点上,对该节点上的直线求凸包,然后对属于该区间的所有询问进行更新。求每一个位置时,在凸包上二分。

题目

hdu 6770杭电多校2020第二场H

题意:动态插入或删除一些形如 f i ( x ) = ( x − a i ) 4 + b i f_{i}(x) = (x - a_{i})^{4} +b_{i} fi(x)=(xai)4+bi的函数,询问某一时刻,某一x对应的函数的最小值。
思路
   g ( x ) = f i ( x ) − f j ( x ) = − 4 ( a i − a j ) x 3 + 6 ( a i 2 − a j 2 ) x 2 − 4 ( a i 3 − a j 3 ) x + ( a i 4 − a j 4 ) + ( b i − b j ) g(x) =f_{i}(x)-f_{j}(x)=-4(a_{i}-a_{j})x^{3}+6(a_{i}^{2}-a_{j}^{2})x^{2}-4(a_{i}^{3}-a_{j}^{3})x+(a_{i}^{4}-a_{j}^{4})+(b_{i}-b_{j}) g(x)=fi(x)fj(x)=4(aiaj)x3+6(ai2aj2)x24(ai3aj3)x+(ai4aj4)+(bibj),其中 a i < a j a_{i}<a_{j} ai<aj
   g ′ ( x ) = − 12 ( a i − a j ) x 2 + 12 ( a i 2 − a j 2 ) x − 4 ( a i 3 − a j 3 ) = − 3 ( a i − a j ) ( 3 x 2 − 3 ( a i + a j ) x + ( a i 2 + a i a j + a j 2 ) ) g'(x)=-12(a_{i}-a_{j})x^{2}+12(a_{i}^{2}-a_{j}^{2})x-4(a_{i}^{3}-a_{j}^{3})=-3(a_{i}-a_{j})(3x^{2}-3(a_{i}+a_{j})x+(a_{i}^{2}+a_{i}a_{j}+a_{j}^{2})) g(x)=12(aiaj)x2+12(ai2aj2)x4(ai3aj3)=3(aiaj)(3x23(ai+aj)x+(ai2+aiaj+aj2))
   Δ = 9 ( a i − a j ) 3 ≤ 0 \Delta=9(a_{i}-a_{j})^{3}\leq0 Δ=9(aiaj)30,所以g(x)单调递减,因此任意 f i f_{i} fi f j f_{j} fj只有一个交点,并且在交点左侧 f i < f j f_{i}<f_{j} fi<fj,在交点右侧 f i > f j f_{i}>f_{j} fi>fj。因此这一类四次函数有了和直线相似的性质,这道题目也就转化成了动态凸包的问题。
  求交点:二分求交点。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10; 
const LL inf = 9e18;
vector <int> vec[N * 4];
int S[N * 2], E[N * 2], st[N * 2], que[N * 2];
LL A[N * 2], B[N * 2], ans[N * 2], Q[N * 2], pst[N * 2];
void update(int x, int l, int r, int ll, int rr, int t)
{
	if(r < ll || rr < l)	return;
	if(ll <= l && r <= rr)	{	vec[x].push_back(t);	return;	}
	int mid = (l + r) >> 1;
	update(x * 2, l, mid, ll, rr, t);
	update(x * 2 + 1, mid + 1, r, ll, rr, t);
}
LL get_f(int id, LL x)
{
	LL a = A[id], b = B[id];
	return (x - a) * (x - a) * (x - a) * (x - a) + b; 
}
LL get_point(int x, int y)
{
	LL l = 0, r = 50001;
	while(r - l > 1)
	{
		LL mid = (l + r) >> 1;
		if(get_f(x, mid) >  get_f(y, mid))	r = mid;
		else	l = mid;
	}
	return l;
}
LL bi_search(int top, LL x)
{
	int l = 1, r = top + 1;
	while(r - l > 1)
	{
		int mid = (l + r) >> 1;
		if(pst[mid] < x)	l = mid;
		else	r = mid;
	}
	LL a = A[st[l]], b = B[st[l]];
	return (x - a) * (x - a) * (x - a) * (x - a) + b;
}
int cmp(int x, int y){	return A[x] < A[y];}
void pushdown(int x, int l, int r)
{
	if(vec[x].size())
	{
		sort(vec[x].begin(), vec[x].end(), cmp);
		st[1] = vec[x][0]; 
		int top = 1;
		for(int i = 1; i < vec[x].size(); i++)
		{
			while(top > 1 && pst[top] >= get_point(st[top], vec[x][i]))	top--;
			st[++top] = vec[x][i];
			pst[top] = get_point(st[top - 1], st[top]);
		}
		for(int i = l; i <= r; i++)
			if(Q[i])
				ans[i] = min(ans[i], bi_search(top, Q[i]));
	}
	if(l == r)	return;
	int mid = (l + r) >> 1;
	pushdown(x * 2, l, mid);
	pushdown(x * 2 + 1, mid + 1, r);
}
int main()
{
	int T, n, m;
	scanf("%d", &T);
	while(T)
	{
		T--;
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; i++)
		{
			scanf("%lld%lld", &A[i], &B[i]);
			S[i] = 1;
		}
		int cnt = 0;
		for(int i = 1; i <= m; i++)
		{
			Q[i] = 0;
			int opt, t;
			LL x;
			scanf("%d", &opt);
			switch(opt)
			{
				case 1:
					n++; scanf("%lld%lld", &A[n], &B[n]); S[n] = i; break;
				case 2:
					scanf("%d", &t); E[t] = i; break;
				case 3:
					scanf("%lld", &x); Q[i] = x; que[++cnt] = i; break;		
			}
		}
		for(int i = 1; i <= m * 4; i++)
			vec[i].clear();
		for(int i = 1; i <= n; i++)
		{
			if(!E[i])	E[i] = m;
			update(1, 1, m, S[i], E[i], i);
		}
		A[n + 1] = 0;
		B[n + 1] = 0;
		for(int i = 1; i <= m; i++)
			ans[i] = inf;
		pushdown(1, 1, m);
		for(int i = 1; i <= cnt; i++)
		{
			if(ans[que[i]] == inf)	cout<<"-1"<<endl;
			else	cout<<ans[que[i]]<<endl;
		}
		for(int i = 1; i <= n; i++)	E[i] = 0;
	}
	return 0;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值