[SDOI2014] 向量集 题解

设加入的第 \(i\) 个向量为 \((a_i,b_i)\),询问的向量是 \((x,y)\),则有(下假设 \(a_i>a_j\)):

\[a_ix+b_iy>a_jx+b_jy \]

\[-(a_i-a_j)x<(b_i-b_j)y \]

\[\begin{cases} \dfrac{b_i-b_j}{a_i-a_j}>-\dfrac xy(y>0)\\ \dfrac{b_i-b_j}{a_i-a_j}<-\dfrac xy(y<0)\\ a_i>a_j(y=0) \end{cases}\]

显然,当 \(y>0\) 时需要维护上凸壳,\(y<0\) 时维护下凸壳,\(y=0\) 时随便。

由于动态加点,所以我们不能直接用线段树预处理出凸壳。但是我们可以只在一个区间被填满时进行凸壳的建立。这样我们就能通过二分查询凸壳上最大值求解了。

时间复杂度 \(O(n\log^2n)\)

#include<bits/stdc++.h>
#define int long long
#define dx(x,y) (xa[x]-xa[y])
#define dy(x,y) (ya[x]-ya[y])
#define gas(x) (xa[x]*a+ya[x]*b)
#define xr 0x7fffffff
using namespace std;
const int N=4e5+5,M=1e6+5;
int n,m,xa[N],ya[N],lst,id[N],sk[N],tp,mx;
namespace up{
	vector<int>st[M];
	int cmp(int x,int y){
		return xa[x]==xa[y]?ya[x]<ya[y]:xa[x]<xa[y];
	}int check(int x,int y,int z){
		return dy(y,x)*dx(z,y)<=dx(y,x)*dy(z,y);
	}void build(int x,int l,int r){
		for(int i=l;i<=r;i++) id[i]=i;
		sort(id+l,id+r+1,cmp);
		for(int i=l;i<=r;sk[++tp]=id[i++])
			while(tp>1&&check(sk[tp-1],sk[tp],id[i])) tp--;
		for(int i=1;i<=tp;i++)
			st[x].push_back(sk[i]);tp=0; 
	}int maxn(int x,int a,int b){
		int l=1,r=st[x].size()-1,ans=0;
		while(l<=r){
			int mid=(l+r)/2;
			if(gas(st[x][mid-1])>gas(st[x][mid])) r=mid-1;
			else l=mid+1,ans=mid;
		}return gas(st[x][ans]);
	}void add(int x,int l,int r){
		if(r==m) build(x,l,r);
		if(l==r) return;int mid=(l+r)/2;
		if(m<=mid) add(x*2,l,mid);
		else add(x*2+1,mid+1,r);
	}int gmax(int x,int l,int r,int L,int R,int a,int b){
		if(L<=l&&r<=R) return maxn(x,a,b);
		int mid=(l+r)/2,re=-1e18;
		if(R>mid) re=gmax(x*2+1,mid+1,r,L,R,a,b);
		if(L<=mid) re=max(re,gmax(x*2,l,mid,L,R,a,b));
		return re;
	}
}namespace down{
	vector<int>st[M];
	int cmp(int x,int y){
		return xa[x]==xa[y]?ya[x]>ya[y]:xa[x]<xa[y];
	}int check(int x,int y,int z){
		return dy(y,x)*dx(z,y)>=dx(y,x)*dy(z,y);
	}void build(int x,int l,int r){
		for(int i=l;i<=r;i++) id[i]=i;
		sort(id+l,id+r+1,cmp);
		for(int i=l;i<=r;sk[++tp]=id[i++])
			while(tp>1&&check(sk[tp-1],sk[tp],id[i])) tp--;
		for(int i=1;i<=tp;i++)
			st[x].push_back(sk[i]);tp=0; 
	}int maxn(int x,int a,int b){
		int l=1,r=st[x].size()-1,ans=0;
		while(l<=r){
			int mid=(l+r)/2;
			if(gas(st[x][mid-1])>gas(st[x][mid])) r=mid-1;
			else l=mid+1,ans=mid;
		}return gas(st[x][ans]);
	}void add(int x,int l,int r){
		if(r==m) build(x,l,r);
		if(l==r) return;int mid=(l+r)/2;
		if(m<=mid) add(x*2,l,mid);
		else add(x*2+1,mid+1,r);
	}int gmax(int x,int l,int r,int L,int R,int a,int b){
		if(L<=l&&r<=R) return maxn(x,a,b);
		int mid=(l+r)/2,re=-1e18;
		if(R>mid) re=gmax(x*2+1,mid+1,r,L,R,a,b);
		if(L<=mid) re=max(re,gmax(x*2,l,mid,L,R,a,b));
		return re;
	}
}int gmax(int x,int y,int l,int r){
	if(y>0) return up::gmax(1,1,mx,l,r,x,y);
	return down::gmax(1,1,mx,l,r,x,y);
}signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	char c;cin>>n>>c,mx=n;
	while(n--){
		char ch;int x,y,l,r;cin>>ch>>x>>y;
		if(c!='E') x^=(lst&xr),y^=(lst&xr);
		if(ch=='Q'){
			cin>>l>>r;if(c!='E') l^=(lst&xr),r^=(lst&xr);
			cout<<(lst=gmax(x,y,l,r))<<"\n";
		}else xa[++m]=x,ya[m]=y,up::add(1,1,mx),down::add(1,1,mx);
	}return 0;
}
posted @ 2025-06-26 11:20  长安一片月_22  阅读(19)  评论(0)    收藏  举报