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$都是可做的(斜率优化型动态规划)

 

 

原文地址:https://www.cnblogs.com/shenben/p/11655855.html