[BZOJ3533][SDOI2014]向量集

bzoj
luogu

description

维护一个向量集,支持在末尾插入一个向量,以及询问\([l,r]\)个插入的向量与\((x,y)\)点积的最大值。强制在线。

sol

\((x,y)\)点积最大的向量一定在凸包上。
所以可以维护区间的上凸壳与下凸壳。
用线段树的方式实现:每插满线段树上的一个区间,就利用两个儿子的凸壳归并建出这个区间的凸壳。查询的话直接在凸壳上二分。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int gi(){
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
#define ll long long
const int N = 4e5+5;
struct point{
	int x,y;
	point(){x=y=0;}
	point(int _x,int _y){x=_x,y=_y;}
	bool operator < (point b)
		{return x<b.x||(x==b.x&&y<b.y);}
	point operator - (point b)
		{return point(x-b.x,y-b.y);}
	ll operator * (point b)
		{return (ll)x*b.y-(ll)y*b.x;}
};
ll dot(point a,point b){
	return (ll)a.x*b.x+(ll)a.y*b.y;
}
vector<point>q1[N<<2],q2[N<<2];int m;ll ans;
void modify(int x,int l,int r,point p){
	if (l==r){
		q1[x].push_back(p);q2[x].push_back(p);
		return;
	}
	int mid=l+r>>1;
	if (m<=mid) modify(x<<1,l,mid,p);else modify(x<<1|1,mid+1,r,p);
	if (m<r) return;
	int u=q1[x<<1].size(),v=q1[x<<1|1].size(),t=-1;
	for (int i=0,j=0;i<u||j<v;)
		if (i<u&&(j==v||q1[x<<1][i]<q1[x<<1|1][j])){
			point tmp=q1[x<<1][i++];
			while (t>0&&(q1[x][t]-q1[x][t-1])*(tmp-q1[x][t])>=0) --t,q1[x].pop_back();
			++t,q1[x].push_back(tmp);
		}else{
			point tmp=q1[x<<1|1][j++];
			while (t>0&&(q1[x][t]-q1[x][t-1])*(tmp-q1[x][t])>=0) --t,q1[x].pop_back();
			++t,q1[x].push_back(tmp);			
		}
	u=q2[x<<1].size(),v=q2[x<<1|1].size(),t=-1;
	for (int i=0,j=0;i<u||j<v;)
		if (i<u&&(j==v||q2[x<<1][i]<q2[x<<1|1][j])){
			point tmp=q2[x<<1][i++];
			while (t>0&&(q2[x][t]-q2[x][t-1])*(tmp-q2[x][t])<=0) --t,q2[x].pop_back();
			++t,q2[x].push_back(tmp);
		}else{
			point tmp=q2[x<<1|1][j++];
			while (t>0&&(q2[x][t]-q2[x][t-1])*(tmp-q2[x][t])<=0) --t,q2[x].pop_back();
			++t,q2[x].push_back(tmp);
		}
}
void calc(int x,point p){
	if (p.y>0){
		int l=1,r=q1[x].size()-1,res=0;
		while (l<=r){
			int mid=l+r>>1;
			if (dot(q1[x][mid],p)>dot(q1[x][mid-1],p)) res=mid,l=mid+1;
			else r=mid-1;
		}
		ans=max(ans,dot(q1[x][res],p));
	}else{
		int l=1,r=q2[x].size()-1,res=0;
		while (l<=r){
			int mid=l+r>>1;
			if (dot(q2[x][mid],p)>dot(q2[x][mid-1],p)) res=mid,l=mid+1;
			else r=mid-1;
		}
		ans=max(ans,dot(q2[x][res],p));
	}
}
void query(int x,int l,int r,int ql,int qr,point p){
	if (l>=ql&&r<=qr) {calc(x,p);return;}
	int mid=l+r>>1;
	if (ql<=mid) query(x<<1,l,mid,ql,qr,p);
	if (qr>mid) query(x<<1|1,mid+1,r,ql,qr,p);
}
int dc(int x){return x^(ans&0X7FFFFFFF);}
int main(){
	int q=gi(),Type=getchar()!='E';
	while (q--){
		char op=getchar();while(op!='A'&&op!='Q')op=getchar();
		if (op=='A'){
			int x=gi(),y=gi();if (Type) x=dc(x),y=dc(y);
			++m;modify(1,1,400000,point(x,y));
		}else{
			int x=gi(),y=gi(),l=gi(),r=gi();
			if (Type) x=dc(x),y=dc(y),l=dc(l),r=dc(r);
			ans=-1ll<<60;query(1,1,400000,l,r,point(x,y));
			printf("%lld\n",ans);
		}
	}
	return 0;
}
posted @ 2018-08-13 16:04  租酥雨  阅读(299)  评论(0编辑  收藏  举报