zoukankan      html  css  js  c++  java
  • SDOI 2014 向量集

    [SDOI2014]向量集

    题目描述

    维护一个向量集合,在线支持以下操作: - "A x y (|x|,|y| < =10^8)":加入向量(x,y); - " Q x y l r (|x|,|y| < =10^8,1 < =L < =R < =T,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。 集合初始时为空。

    输入输出格式

    输入格式

    输入的第一行包含整数N和字符s,分别表示操作数和数据类别; 接下来N行,每行一个操作,格式如上所述。 请注意s≠'E'时,输入中的所有整数都经过了加密。你可以使用以下程序得到原始输入: ··· inline int decode (int x long long lastans) { return x ^ (lastans & Ox7fffffff); } ``` 其中x为程序读入的数,lastans为之前最后一次询问的答案。在第一次询问之前,lastans=0。注:向量(x,y)和(z,W)的点积定义为xz+yw。

    输出格式

    对每个Q操作,输出一个整数表示答案。

    输入输出样例

    输入样例 #1

    6 A
    A 3 2
    Q 1 5 1 1
    A 15 14
    A 12 9
    Q 12 8 12 15
    Q 21 18 19 18

    输出样例 #1

    13
    17
    17
    

    说明

    样例解释:解密之后的输入为 ``` 6 E A 3 2 Q 1 5 1 1 A 2 3 A 1 4 Q 1 5 1 2 Q 4 3 2 3 ``` 1 < =N < =4*10^5

    [题意]

    维护向量序列,支持在序列末尾添加向量,以及询问某个区间中的向量与给定向量的点积的最大值。

    [官方题解]

    [个人题解](网上东拼西凑的)


    一般性设当前询问的$y_0>0$,那么$dfrac{ans}{y_0}=max{dfrac{x_0}{y_0}cdot x+y}$,然后这个东西和斜率优化长得一样,答案一定是在凸壳上的.

    于是我们维护这个凸壳.因为有区间询问所以线段树维护每个区间的凸壳.具体地,插入的时候统计当前区间已经有多少个点,如果点数等于当前区间长度那么构造出这个区间的凸壳.询问的时候拆成$log$个区间分别跑二分/三分即可.

    求凸包这里使用按$x$坐标排序的那个算法.注意如果几个点的$x$相同那么要按$y$排序.

    插入的时候每个区间只会被构建一次凸包,总复杂度$O(nlog n)$,排序用归并.

    查询的时候拆成$log$个区间,每个区间$O(log n)$三分/二分,总复杂度$O(nlog ^2 n)$

    每个区间都要构建一次凸包,可以这么处理:每个线段树节点放个指针,动态开辟空间建立凸包。

    网上不少代码把情况讨论合并成一种,只维护上凸壳。保险起见,也为了自己能够更好地理解,我还是分类讨论,同时维护上下凸壳。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    inline void read(int &x){
        register char ch=getchar();x=0;register bool f=0;
        for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
        if(f) x=-x;
    }
    const int N=4e5+3;
    int n,m,cnt;ll ans;char type[3],op[3];
    struct Q{
        int opt,l,r,x,y;
        Q(){}
        Q(int opt,int l,int r,int x,int y):opt(opt),l(l),r(r),x(x),y(y){}
    }q[N];
    struct point{
        int x,y;
        point(int x=0,int y=0):x(x),y(y){}
        point operator +(const point &a)const{
            return point(x+a.x,y+a.y);
        }
        point operator -(const point &a)const{
            return point(x-a.x,y-a.y);
        }
        ll operator *(const point &a)const{
            return (ll)x*a.x+(ll)y*a.y;
        }
        ll operator ^(const point &a){
            return (ll)x*a.y-(ll)y*a.x;
        }
        bool operator <(const point &a)const{
            return x==a.x?y<a.y:x<a.x;
        }
    }p[N],tmp[N];int tmpsize;
    struct CH{
        point *up,*dw;
        int upsize,dwsize;
        void init(int l,int r){
            up=new point[r-l+2];
            dw=new point[r-l+2];
            tmpsize=upsize=dwsize=0;
            for(int i=l;i<=r;i++) tmp[++tmpsize]=p[i];
            sort(tmp+1,tmp+tmpsize+1);
            for(int i=1;i<=tmpsize;i++){
                for(;upsize>1&&((tmp[i]-up[upsize])^(up[upsize]-up[upsize-1]))<=0;upsize--);
                up[++upsize]=tmp[i];
                for(;dwsize>1&&((dw[dwsize]-dw[dwsize-1])^(tmp[i]-dw[dwsize]))<=0;dwsize--);
                dw[++dwsize]=tmp[i];
            }
        }
        ll qmax(point p){
            int l,r,mid1,mid2;ll res=-(1LL<<62);
            if(p.y>=0){
                l=1;r=upsize;
                while(r-l>2){
                    mid1=l+(r-l)/3;
                    mid2=r-(r-l)/3;
                    if(up[mid1]*p<up[mid2]*p)
                        l=mid1;
                    else
                        r=mid2;
                }
                for(int i=l;i<=r;i++) res=max(res,up[i]*p);
            }
            else{
                l=1;r=dwsize;
                while(r-l>2){
                    mid1=l+(r-l)/3;
                    mid2=r-(r-l)/3;
                    if(dw[mid1]*p<dw[mid2]*p)
                        l=mid1;
                    else
                        r=mid2;
                }
                for(int i=l;i<=r;i++) res=max(res,dw[i]*p);
            }
            return res;
        }
    }b[N<<2];bool tag[N<<2];
    #define lch k<<1
    #define rch k<<1|1
    ll query(int k,int l,int r,int x,int y,point p){
        if(l==x&&r==y){
            if(!tag[k]) tag[k]=1,b[k].init(l,r);
            return b[k].qmax(p);
        }
        int mid=l+r>>1;
        if(y<=mid) return query(lch,l,mid,x,y,p);
        else if(x>mid) return query(rch,mid+1,r,x,y,p);
        else return max(query(lch,l,mid,x,mid,p),query(rch,mid+1,r,mid+1,y,p));
    }
    inline void decode(int &x){
        if(type[0]=='E') return ;
        x=x^(ans&0x7fffffff);
    }
    int main(){
        read(m);scanf("%s",type);
        for(int i=1,opt,x,y,l,r;i<=m;i++){
            scanf("%s",op);opt=(op[0]=='Q');
            if(opt){
                read(x);read(y);
                read(l);read(r);
            }
            else{
                read(x);read(y);l=r=0;
                ++n;
            }
            q[i]=Q(opt,l,r,x,y);
        }
        for(int i=1,l,r,x,y;i<=m;i++){
            if(q[i].opt){
                l=q[i].l;r=q[i].r;
                x=q[i].x;y=q[i].y;
                decode(l);decode(r);
                decode(x);decode(y);
                ans=query(1,1,n,l,r,point(x,y));
                printf("%lld
    ",ans);
            }
            else{
                x=q[i].x;y=q[i].y;
                decode(x);decode(y);
                p[++cnt]=point(x,y);
            }
        }
        return 0;
    }

    收获:

    所有形如$f[i]=minlimits_{L(i)leq jleq R(i)}{k(i)x(j)+F(j)}+G(i)$的$dp$都是可做的(斜率优化型动态规划)

     

     

  • 相关阅读:
    从jvm的角度来看java的多线程
    jvm常用优化方案和方法
    JVM GC 机制与性能优化
    JVM 类加载机制详解
    (转)Java 详解 JVM 工作原理和流程
    Callable,Runnable异同
    使用Toast进行用户提醒(转)
    学好Java只需要做到这7点,年薪20W起步
    C# 之泛型详解
    C#中的委托和事件
  • 原文地址:https://www.cnblogs.com/shenben/p/11655855.html
Copyright © 2011-2022 走看看