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\n",ans[i]);
    return 0;
}

 

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

+本文作者:luyouqi233。               +

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

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

posted @ 2018-05-25 10:07  luyouqi233  阅读(321)  评论(0编辑  收藏  举报