• BZOJ4311:向量——题解


    https://www.lydsy.com/JudgeOnline/problem.php?id=4311

    你要维护一个向量集合,支持以下操作:
    1.插入一个向量(x,y)
    2.删除插入的第i个向量
    3.查询当前集合与(x,y)点积的最大值是多少。如果当前是空集输出0

    半个论文题吧……另外当空集的时候没有及时跳出结果WA了debug很难受。

    参考:https://blog.csdn.net/outer_form/article/details/52277030

    首先,每个向量都在第一象限,然后根据点积的基本定义,实际上就是给定向量与其他向量投影到给定向量的长度的乘积。

    故在向量的无穷远处取一点,过这个点做垂线,然后将垂线往原点移,最先扫到的向量就是答案。

    于是我们可以发现答案一定在点集的凸包上。

    然而对于每个向量生效时间段不一样,所以我们把点排序后(这样建凸包的时候就不用再排序了)按时间建立线段树完后把点扔上去,然后对于每个区间的点集建立凸包跑一遍。

    另外我们还可以发现把询问向量极角排序之后决策点单调(显然决策点是从凸包靠下的点慢慢变成靠上的点),于是跑一遍就可以了。

    对于向量的极角排序正好用归并排序连同爬线段树一起做了,所以复杂度为O(nlogn)。

    #include<cmath>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=2e5+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct point{
        ll x,y;
        point(){}
        point(ll a,ll b){x=a,y=b;}
        point operator-(const point &b)const{
            return point(x-b.x,y-b.y);
        }
    }q[N],s[N];
    struct data{
        point a;
        int l,r;
    }p[N];
    int n,pcnt,qcnt,tmp[N],t[N];
    vector<point>tr[N*4];
    ll ans[N];
    inline ll multiX(point a,point b){
        return a.x*b.y-b.x*a.y;
    }
    inline ll multiP(point a,point b){
        return a.x*b.x+a.y*b.y;
    }
    inline bool cmp(data a,data b){
        point u=a.a,v=b.a;
        return u.x>v.x||(u.x==v.x&&u.y>v.y);
    }
    void insert(int a,int l,int r,int l1,int r1,point x){
        if(r<l1||r1<l)return;
        if(l1<=l&&r<=r1){
        tr[a].push_back(x);return;
        }
        int mid=(l+r)>>1;
        insert(a<<1,l,mid,l1,r1,x);insert(a<<1|1,mid+1,r,l1,r1,x);
    }
    void divide(int a,int l,int r){
        if(l==r){
        tmp[l]=l;
        for(int i=0;i<tr[a].size();i++)
            ans[l]=max(ans[l],multiP(q[l],tr[a][i]));
        return;
        }
        int mid=(l+r)>>1;
        divide(a<<1,l,mid);divide(a<<1|1,mid+1,r);
        for(int i=l,j=l,k=mid+1;i<=r;i++){
        if(j<=mid&&(k>r||multiX(q[tmp[j]],q[tmp[k]])>=0))t[i]=tmp[j++];
        else t[i]=tmp[k++];
        }
        for(int i=l;i<=r;i++)tmp[i]=t[i];
        int rr=0;
        for(int i=0;i<tr[a].size();i++){
        while(rr>1&&multiX(tr[a][i]-s[rr-1],s[rr]-s[rr-1])>=0)rr--;
        s[++rr]=tr[a][i];
        }
        if(rr){
        for(int i=l,j=1;i<=r;i++){
            while(j<rr&&multiP(q[tmp[i]],s[j+1])>multiP(q[tmp[i]],s[j]))j++;
            ans[tmp[i]]=max(ans[tmp[i]],multiP(q[tmp[i]],s[j]));
        }
        }
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++){
        int op=read();
        if(op==1){
            int x=read(),y=read();
            p[++pcnt].a=point(x,y);
            p[pcnt].l=qcnt+1;
            p[pcnt].r=-1;
        }
        if(op==2){
            int id=read();
            p[id].r=qcnt;
        }
        if(op==3){
            int x=read(),y=read();
            q[++qcnt]=point(x,y);
        }
        }
        sort(p+1,p+pcnt+1,cmp);
        for(int i=1;i<=pcnt;i++){
        if(p[i].r==-1)p[i].r=qcnt;
        if(p[i].l>p[i].r)continue;
        insert(1,1,qcnt,p[i].l,p[i].r,p[i].a);
        }
        divide(1,1,qcnt);
        for(int i=1;i<=qcnt;i++)printf("%lld
    ",ans[i]);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    PAT(A) 1095. Cars on Campus (30)
    PAT(A) 1080. Graduate Admission (30)
    PAT(A) 1083. List Grades (25)
    Linux 使用create_ap开热点后无法连接wifi问题的解决
    汽车加油行驶问题(最短路)
    孤岛营救问题(最短路 状态压缩)  网络流24题
    软件补丁问题(状态压缩 最短路)
    餐巾计划问题(费用流)
    分配问题(二部图的最佳匹配 KM) 线性规划与网络流24题
    数字梯形问题(费用流)
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9086969.html
Copyright © 2020-2023  润新知