[SDOI2014] 向量集

题意:

维护一个向量集合,在线支持以下操作:

  1. A x y:加入向量$(x,y)$。
  2. Q x y L R:询问第L个到第R个加入的向量与向量$(x,y)$的点积的最大值。集合初始时为空。

$nleq 4 imes 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(nlog^{2}{n})$。

套路:

  • 形如$xa+yb$的式子$ ightarrow$求个凸壳。
  • 形如栈式插入的线段树$ ightarrow$只在一个节点插满时维护信息。
  • 注意输入字符时最好用$cin$,如果用$scanf$好像不能换行?

代码:

#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
",lans);
        }
    } 
    return 0;
}
向量集
原文地址:https://www.cnblogs.com/YSFAC/p/13188663.html