[SDOI2014] 向量集
题意:
维护一个向量集合,在线支持以下操作:
- A x y:加入向量$(x,y)$。
- Q x y L R:询问第L个到第R个加入的向量与向量$(x,y)$的点积的最大值。集合初始时为空。
$n\leq 4\times 10^{5}$。
题解:
令输入点为$(a,b)$,所求点为$(x,y)$,则所求最大点积为$ans=xa+yb$。变式,得$y=\frac{a}{b}x+\frac{ans}{b}$。
考虑该式的几何意义,容易发现是用一条斜率为$\frac{a}{b}$的直线向上平移,满足与集合中的点有交,求最大/最小截距。
那么显然在求最大截距($b>0$)时答案在上凸壳上,最小截距($b<0$)时答案在下凸壳上。
于是用线段树维护每个区间的上下凸壳即可,由于查询的区间一定是满的,所以每个区间只需要在插满点的时候求一次凸壳。
查询时在线段树上三分,注意整数三分需要区间长度$\geq 4$。
复杂度$O(n\log^{2}{n})$。
套路:
- 形如$xa+yb$的式子$\rightarrow$求个凸壳。
- 形如栈式插入的线段树$\rightarrow$只在一个节点插满时维护信息。
- 注意输入字符时最好用$cin$,如果用$scanf$好像不能换行?
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define maxn 400005 #define maxm 500005 #define inf 0x7fffffff #define ll long long #define rint register ll #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define dgx cerr<<"=============="<<endl using namespace std; struct node{ ll x,y; node operator+(const node b)const{return (node){x+b.x,y+b.y};} node operator-(const node b)const{return (node){x-b.x,y-b.y};} ll operator*(const node b)const{return x*b.y-y*b.x;} ll operator^(const node b)const{return x*b.x+y*b.y;} }A[maxn],S[maxn]; vector<node> trup[maxn<<2],trdw[maxn<<2]; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline bool cmp(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;} inline ll decode(ll x,ll lans){return x^(lans&inf);} inline void build(ll k){ ll n=0,top=0; for(ll i=0;i<trup[k<<1].size();i++) A[++n]=trup[k<<1][i]; for(ll i=0;i<trup[k<<1|1].size();i++) A[++n]=trup[k<<1|1][i]; sort(A+1,A+1+n,cmp); for(ll i=1;i<=n;S[++top]=A[i++]) while(top>=2 && (A[i]-S[top])*(S[top]-S[top-1])<=0) top--; for(ll i=1;i<=top;i++) trup[k].push_back(S[i]); n=0,top=0; for(ll i=0;i<trdw[k<<1].size();i++) A[++n]=trdw[k<<1][i]; for(ll i=0;i<trdw[k<<1|1].size();i++) A[++n]=trdw[k<<1|1][i]; sort(A+1,A+1+n,cmp); for(ll i=1;i<=n;S[++top]=A[i++]) while(top>=2 && (A[i]-S[top])*(S[top]-S[top-1])>=0) top--; for(ll i=1;i<=top;i++) trdw[k].push_back(S[i]); } inline ll calc(ll k,node a){ if(a.y>0){ ll l=1,r=trup[k].size(),ans=-(1ll<<62); while(r-l+1>=4){ ll p1=(l+l+r)/3,p2=(l+r+r)/3; ((trup[k][p1-1]^a)>(trup[k][p2-1]^a))?r=p2:l=p1; } for(int i=l;i<=r;i++) ans=max(ans,trup[k][i-1]^a); return ans; } else{ ll l=1,r=trdw[k].size(),ans=-(1ll<<62); while(r-l+1>=4){ ll p1=(l+l+r)/3,p2=(l+r+r)/3; ((trdw[k][p1-1]^a)>(trdw[k][p2-1]^a))?r=p2:l=p1; } for(int i=l;i<=r;i++) ans=max(ans,trdw[k][i-1]^a); return ans; } } inline void ins(ll x,node a,ll l,ll r,ll k){ if(l==r){trup[k].push_back(a),trdw[k].push_back(a);return;} ll mid=l+r>>1; if(x<=mid) ins(x,a,l,mid,k<<1); else ins(x,a,mid+1,r,k<<1|1); if(x==r) build(k); } inline ll qry(ll x,ll y,node a,ll l,ll r,ll k){ if(x<=l && r<=y) return calc(k,a); ll mid=l+r>>1,res=-(1ll<<62); if(x<=mid) res=max(res,qry(x,y,a,l,mid,k<<1)); if(y>mid) res=max(res,qry(x,y,a,mid+1,r,k<<1|1)); return res; } int main(){ ll n=read(),tot=0,lans=0; char ch; cin>>ch; for(ll i=1;i<=n;i++){ char op; cin>>op; if(op=='A'){ node tp; tp.x=read(),tp.y=read(); if(ch!='E') tp.x=decode(tp.x,lans),tp.y=decode(tp.y,lans); ins(++tot,tp,1,n,1); } else{ node tp; tp.x=read(),tp.y=read(); if(ch!='E') tp.x=decode(tp.x,lans),tp.y=decode(tp.y,lans); ll l=read(),r=read(); if(ch!='E') l=decode(l,lans),r=decode(r,lans); lans=qry(l,r,tp,1,n,1),printf("%lld\n",lans); } } return 0; }