bzoj3533 [Sdoi2014]向量集 可持久化凸包+二分

首先,x和y都小于一个向量且都大于一个向量的点一定是没有用的

这样就相当于挖掉了决策中位置偏中间的点,然后要求ax+by的最小值

设 ax+by=k,则 y=k/b-a/bx  ,就变成了类似斜率优化的东西,相当于拿一个斜率去卡一个点

卡的点一定在凸包上,所以维护凸包,然后二分斜率查询就可以了

这个题要求支持查询历史版本的凸包,可以用线段树的思想,树分治的复杂度分析方法,将最终凸包2分成若干层独立凸包

然后由于答案是有凸包组成的,不会多点,所以直接在每个凸包上查询即可

非常难写,写代码一定要仔细


码:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define zuo o<<1,l,mid
#define you o<<1|1,mid+1,r
#define eps 0.0000000000000005
#define N 400005
long double xx,yy,c,d;
long long daan;
int a,b,x,y,op,n,i,cnt;
bool wc[N<<2];
char lx,ch;
struct dian
{
long double x,y;	
}q[N];
vector<dian>v[N<<2],v2[N<<2];
long double xl(dian a,dian b)
{
	
	if(a.x==b.x)return 100000000000000007;
	return (a.y-b.y)/(a.x-b.x);	
}
void up(int o)
{
int ll=o<<1,rr=o<<1|1;
if(wc[ll]&&wc[rr]&&wc[o]==0)
{
int sx=v[ll].size()+v[rr].size(),zz=0,i,l1=0,l2=0;//上凸 
for(i=1;i<=sx;i++)
{
	dian d1,d2;
	if(l1==v[ll].size())
	{
	d1.x=1000000000;d1.y=0;l1++;
	}else d1=v[ll][l1],l1++;
		if(l2==v[rr].size())
	{
	d2.x=1000000000;d2.y=0;l2++;
	}else d2=v[rr][l2],l2++;
	if(d1.x<d2.x||(d1.x==d2.x&&d1.y<d2.y))l2--;else l1--,swap(d1,d2);
	while(zz>=2&&xl(d1,q[zz-1])+eps>xl(q[zz-1],q[zz]))zz--;	
	q[++zz]=d1;
}
for(i=1;i<=zz;i++)
v[o].push_back(q[i]);
	sx=v2[ll].size()+v2[rr].size(),zz=0,i,l1=0,l2=0;//下凸 
for(i=1;i<=sx;i++)
{
	dian d1,d2;
	if(l1==v2[ll].size())
	{
	d1.x=1000000000;d1.y=0;l1++;
	}else d1=v2[ll][l1],l1++;
		if(l2==v2[rr].size())
	{
	d2.x=1000000000;d2.y=0;l2++;
	}else d2=v2[rr][l2],l2++;
	if(d1.x<d2.x||(d1.x==d2.x&&d1.y<d2.y))l2--;else l1--,swap(d1,d2);
	while(zz>=2&&xl(d1,q[zz-1])<xl(q[zz-1],q[zz])+eps)zz--;	
	q[++zz]=d1;
}
for(i=1;i<=zz;i++)
v2[o].push_back(q[i]);
wc[o]=1;
}	
}
void gai(int o,int l,int r)
{
if(a<=l&&r<=b&&op==0)
{
		dian lin;
		lin.x=c;lin.y=d;		
		v[o].push_back(lin);
		v2[o].push_back(lin);	
		wc[o]=1;	
	return ;
}	
if(a<=l&&r<=b&&op==1&&wc[o])
{	
	if(yy>0)//找shang凸壳	
		{
	int ll=1,rr=v[o].size()-1,ans=0;	
	c=max(c,xx*v[o][0].x+yy*v[o][0].y);
	c=max(c,xx*v[o][rr].x+yy*v[o][rr].y);	
	while(ll<rr)
	{
	int mid=(ll+rr)>>1;
	if(xl(v[o][mid],v[o][mid-1])+eps>-xx/yy)
	{
	ans=mid;	
	ll=mid+1;
	}else rr=mid;	
	}
	c=max(c,v[o][ans].x*xx+v[o][ans].y*yy);		
	    }else//下凸壳 
	    {
	    	
	   	int ll=1,rr=v2[o].size()-1,ans=0;	
	c=max(c,xx*v2[o][0].x+yy*v2[o][0].y);
	c=max(c,xx*v2[o][rr].x+yy*v2[o][rr].y);	
	while(ll<rr)
	{
	int mid=(ll+rr)>>1;
	if(xl(v2[o][mid],v2[o][mid-1])<-xx/yy+eps)
	{
	ans=mid;	
	ll=mid+1;
	}else rr=mid;	
	}
	c=max(c,v2[o][ans].x*xx+v2[o][ans].y*yy);	 	 	
		}	
		return;
}
int mid=(l+r)>>1;
if(a<=mid)gai(zuo);
if(b>mid)gai(you);
up(o);	
}
inline int decode (int x ) {
     return x ^ (daan & 2147483647);
}
int main()
{
scanf("%d%c",&n,&lx);
while(lx==' ')scanf("%c",&lx);
for(i=1;i<=n;i++)
{	
scanf("%c",&ch);while(ch!='A'&&ch!='Q')scanf("%c",&ch);
if(ch=='A')
{
scanf("%d%d",&x,&y);
if(lx!='E')x=decode(x),y=decode(y);
a=b=++cnt;	op=0;c=x,d=y;
gai(1,1,n);
}	
if(ch=='Q')
{
scanf("%d%d%d%d",&x,&y,&a,&b);
if(lx!='E')x=decode(x),y=decode(y),a=decode(a),b=decode(b);xx=x;yy=y;
op=1;c=-100000000000000007;  
 gai(1,1,n);	
daan=c;
printf("%lld\n",daan);
}
}		
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值