[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;
}

浙公网安备 33010602011771号