zoukankan      html  css  js  c++  java
  • [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;
    }
    向量集
  • 相关阅读:
    ubuntu 无法在终端切换输入法的解决办法
    c代码连接mysql数据库内存泄露的问题
    栈和堆的地址哪个高
    笔试题之union与struct
    笔试题之interface和abstract class之间的区别
    笔试题之C#struct
    c++单例模式的写法
    c++返回引用是否是真的引用
    operator = 为什么要返回*this的应用
    c++ new和delete操作符的重载
  • 原文地址:https://www.cnblogs.com/YSFAC/p/13188663.html
Copyright © 2011-2022 走看看