[BZOJ3533]向量集

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3533]向量集相关的知识,希望对你有一定的参考价值。

首先,答案在凸包上为啥?去问ypl

然后点积结果是单峰的所以我们可以用三分查找(为了三分方便,我们要分别维护上下凸壳而不是极角序凸包)

查询区间,所以用线段树维护

动态维护要用高端数据结构,不方便三分,所以我们可以稍微延迟一点

具体点:因为此题的查询有特殊性质,即右端点不会大于当前已加入的数量,所以每当当前加入点到达了某些线段树节点的区间右端点才把整个区间的凸包建好(这样建凸包可以用数组存,方便三分)

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
struct point{
	int x,y;
	point(int a=0,int b=0){
		x=a;
		y=b;
	}
}p[400010],stack[400010];
ll operator*(point&a,point&b){
	return a.x*(ll)b.x+a.y*(ll)b.y;
}
ll operator/(point a,point b){
	return a.x*(ll)b.y-a.y*(ll)b.x;
}
point operator-(point&a,point&b){
	return point(a.x-b.x,a.y-b.y);
}
typedef vector<point> vp;
vp up[1600010],down[1600010];
ll lastans;
int l[400010],r[400010],top;
bool op[400010];
void decode(int&x){
	x^=lastans&0x7fffffff;
}
bool cmp1(point a,point b){
	if(a.x==b.x)return a.y<b.y;
	return a.x<b.x;
}
void getup(vp&v){
	if(v.size()==0)return;
	sort(v.begin(),v.end(),cmp1);
	top=1;
	stack[0]=v[0];
	int i;
	for(i=1;i<v.size();i++){
		while(top>1&&(stack[top-1]-stack[top-2])/(v[i]-stack[top-1])>=0)top--;
		stack[top]=v[i];
		top++;
	}
	v.clear();
	for(i=0;i<top;i++)v.push_back(stack[i]);
}
bool cmp2(point a,point b){
	if(a.x==b.x)return a.y>b.y;
	return a.x<b.x;
}
void getdown(vp&v){
	if(v.size()==0)return;
	sort(v.begin(),v.end(),cmp2);
	top=1;
	stack[0]=v[0];
	int i;
	for(i=1;i<v.size();i++){
		while(top>1&&(stack[top-1]-stack[top-2])/(v[i]-stack[top-1])<=0)top--;
		stack[top]=v[i];
		top++;
	}
	v.clear();
	for(i=0;i<top;i++)v.push_back(stack[i]);
}
void modify(int pos,point&p,int l,int r,int x){
	up[x].push_back(p);
	down[x].push_back(p);
	if(pos==r){
		getup(up[x]);
		getdown(down[x]);
	}
	if(l==r)return;
	int mid=(l+r)>>1;
	if(pos<=mid)
		modify(pos,p,l,mid,x<<1);
	else
		modify(pos,p,mid+1,r,x<<1|1);
}
ll solve(int x,point&p){
	int i,l,r,m1,m2;
	ll ans=-9223372036854775807ll;
	if(p.y>0){
		l=0;
		r=up[x].size()-1;
		while(r-l>2){
			m1=((l<<1)+r)/3;
			m2=(l+(r<<1))/3;
			if(up[x][m1]*p<up[x][m2]*p)
				l=m1;
			else
				r=m2;
		}
		for(i=l;i<=r;i++)ans=max(ans,up[x][i]*p);
	}else{
		l=0;
		r=down[x].size()-1;
		while(r-l>2){
			m1=((l<<1)+r)/3;
			m2=(l+(r<<1))/3;
			if(down[x][m1]*p<down[x][m2]*p)
				l=m1;
			else
				r=m2;
		}
		for(i=l;i<=r;i++)ans=max(ans,down[x][i]*p);
	}
	return ans;
}
ll query(int L,int R,point&p,int l,int r,int x){
	if(L<=l&&r<=R)return solve(x,p);
	int mid=(l+r)>>1;
	ll ans=-9223372036854775807ll;
	if(L<=mid)ans=max(ans,query(L,R,p,l,mid,x<<1));
	if(mid<R)ans=max(ans,query(L,R,p,mid+1,r,x<<1|1));
	return ans;
}
int main(){
	int n,m,i,now;
	char s[5];
	bool sec=0;
	scanf("%d%s",&m,s);
	if(s[0]!=‘E‘)sec=1;
	n=0;
	for(i=1;i<=m;i++){
		scanf("%s%d%d",s,&p[i].x,&p[i].y);
		op[i]=s[0]==‘A‘;
		if(op[i])
			n++;
		else
			scanf("%d%d",l+i,r+i);
	}
	now=0;
	for(i=1;i<=m;i++){
		if(sec){
			decode(p[i].x);
			decode(p[i].y);
		}
		if(op[i]){
			now++;
			modify(now,p[i],1,n,1);
		}else{
			if(sec){
				decode(l[i]);
				decode(r[i]);
			}
			printf("%lld\n",lastans=query(l[i],r[i],p[i],1,n,1));
		}
	}
}

以上是关于[BZOJ3533]向量集的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3533: [Sdoi2014]向量集

BZOJ 3533 [Sdoi2014]向量集

BZOJ3533: [Sdoi2014]向量集

BZOJ 3533 sdoi 2014 向量集

[BZOJ3533]向量集

引用向量的部分片段?