Bzoj3533:[Sdoi2014]向量集:线段树+凸包+三分

本文介绍了一道名为Sdoi2014向量集的问题的解决方案,采用线段树维护区间上的凸壳,并通过三分法求解最大值。代码实现了线段树的构建、更新及查询过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接[Sdoi2014]向量集

维护一颗线段树,线段树每个节点上有对应区间的上下凸壳

可以发现答案一定在凸壳上取得,所以在凸壳上三分即可,y>=0时在上凸壳上三分,否则在下凸壳

#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
#define pii pair<ll,ll>
#define mp make_pair
#define dc(x) ((x)^(ans&0x7fffffff))
using namespace std;
const int maxn=400010;
const ll inf=1e17;
struct seg{
	int l,r,mr;
	vector< pii >vu;
	vector< pii >vd;
	seg *lc,*rc;
};
seg *root=new seg();
int n,sta[maxn],opt,cnt=0,l[maxn],r[maxn];
ll X[maxn],Y[maxn],ans=0;
char c,s[maxn];
struct point{ll x,y;}po[maxn],tmpp[maxn];

ll cross(ll a,ll b,ll c,ll d,ll e,ll f){
	ll x1=c-a,y1=d-b;
	ll x2=e-a,y2=f-b;
	return 1ll*x1*y2-1ll*x2*y1;
}

void build(seg *p,int l,int r){
	p->l=l; p->r=r;
	if (l+1==r){
		p->lc=p->rc=NULL; return;
	}else if (l+1<r){
		int mid=(l+r)>>1;
		p->lc=new seg();
		p->rc=new seg();
		if (l<mid) build(p->lc,l,mid);
		if (mid<r) build(p->rc,mid,r);
	}
}

bool cmp(const point &a,const point &b){
	return a.x<b.x||(a.x==b.x&&a.y<b.y);
}

void make_convex(seg *p,int l,int r){
	if (r-l+1<=5){
		for (int i=l;i<=r;++i) p->vu.pb(mp(po[i].x,po[i].y));
		for (int i=l;i<=r;++i) p->vd.pb(mp(po[i].x,po[i].y));
	}else{
		for (int i=l;i<=r;++i) tmpp[i]=po[i];
		sort(po+l,po+r+1,cmp);		
		int top=0;
		sta[++top]=l; sta[++top]=l+1;
		for (int i=l+2;i<=r;++i){
		    while (top>1&&cross(po[sta[top-1]].x,po[sta[top-1]].y,po[sta[top]].x,po[sta[top]].y,po[i].x,po[i].y)>0) top--;
		    sta[++top]=i;
		}
		for (int i=1;i<=top;++i) p->vu.pb(mp(po[sta[i]].x,po[sta[i]].y));
		top=0; sta[++top]=r; sta[++top]=r-1;
		for (int i=r-2;i>=l;--i){
			while (top>1&&cross(po[sta[top-1]].x,po[sta[top-1]].y,po[sta[top]].x,po[sta[top]].y,po[i].x,po[i].y)>0) top--;
			sta[++top]=i;
		}
		for (int i=1;i<=top;++i) p->vd.pb(mp(po[sta[i]].x,po[sta[i]].y));
		for (int i=l;i<=r;++i) po[i]=tmpp[i];
	}
}

void add(seg *p,int l,int r){
	if (l<=p->l&&p->r<=r){
		p->mr=r; make_convex(p,l,r-1); return;
	}else{
		int mid=(p->l+p->r)>>1;
		if (l<mid) add(p->lc,l,r);
		if (mid<r) add(p->rc,l,r);
		p->mr=p->rc->mr;
		if (p->mr==p->r) make_convex(p,p->l,p->r-1);
	}
}

ll getval(pii p,ll x,ll y){
	return 1ll*p.first*x+1ll*p.second*y;
}

void worku(seg *p,ll x,ll y){
	if (p->r-p->l<=5){
		for (int i=0;i<p->vu.size();++i) ans=max(ans,getval(p->vu[i],x,y));
	}
	int l=0,r=p->vu.size()-1;
	while (r-l>=3){
		int ml=(l+l+r)/3,mr=(l+r+r)/3;
		if (getval(p->vu[ml],x,y)<=getval(p->vu[mr],x,y)) l=ml;
		else r=mr;
	}
	for (int i=l;i<=r;++i) ans=max(ans,getval(p->vu[i],x,y));
}

void workd(seg *p,ll x,ll y){
	if (p->r-p->l<=5){
		for (int i=0;i<p->vd.size();++i) ans=max(ans,getval(p->vd[i],x,y));
	}
	int l=0,r=p->vd.size()-1;
	while (r-l>=3){
		int ml=(l+l+r)/3,mr=(l+r+r)/3;
		if (getval(p->vd[ml],x,y)<=getval(p->vd[mr],x,y)) l=ml;
		else r=mr;
	}
	for (int i=l;i<=r;++i) ans=max(ans,getval(p->vd[i],x,y));
}

void ask(seg *p,int l,int r,ll x,ll y){
	if (l<=p->l&&p->r<=r){
		if (y>=0) worku(p,x,y);
		else workd(p,x,y);
		return;
	}
	int mid=(p->l+p->r)>>1;
	if (l<mid) ask(p->lc,l,r,x,y);
	if (mid<r) ask(p->rc,l,r,x,y);
}

int main(){
	scanf("%d",&n); cin>>c;
	if (c=='E') opt=0; else opt=1;
	for (int i=1;i<=n;++i){
		cin>>s[i];
		if (s[i]=='A'){
			++cnt; scanf("%lld%lld",&po[cnt].x,&po[cnt].y);
		}else if (s[i]=='Q'){
			scanf("%lld%lld%d%d",&X[i],&Y[i],&l[i],&r[i]);
		}
	}
	build(root,1,cnt+1);
	int now=1;
	for (int i=1;i<=n;++i){
		if (s[i]=='A'){
			if (opt) po[now].x=dc(po[now].x),po[now].y=dc(po[now].y);
			add(root,now,now+1); now++;
		}else if (s[i]=='Q'){
			if (opt) X[i]=dc(X[i]),Y[i]=dc(Y[i]),l[i]=dc(l[i]),r[i]=dc(r[i]);
			ans=-inf;
			ask(root,l[i],r[i]+1,X[i],Y[i]);
			printf("%lld\n",ans);
		}
	}
}