Sdoi2014 向量集

题目描述

题解:

码力太差重构之后才$A……$

首先求向量点积最大很容易想到凸包,

设已知$(x_0,y_0)$,求$(x,y)$满足$(x,y)*(x_0,y_0)>=(x',y')*(x_0,y_0)$

设$(x,y)*(x_0,y_0)=c$

那么$x*x_0+y*y_0=c$,$y=frac(-x_0,y_0)*x+frac(c,x_0)$

所以$x_0>0$时,$b$取最大,维护上凸包;

$x_0<0$时,$b$取最小,维护下凸包。

其实$x_0=0$不需要单独维护,放到任意一堆里二分都行。

由于询问与时间序有关,我们可以按时间建线段树,

每个节点挂一个凸包。

每次询问时从对应凸包二分查最大点积。

插入时并不需要每插一个点就把这个凸包拆开重构,

只需要在子树插满,即$r=x$时建立凸包即可。

代码:

#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 400050;
typedef long long ll;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const double eps = 1e16;
int n,tot;
ll ans;
char s0[5],s[5];
struct Point
{
    ll x,y;
    Point(){}
    Point(ll x,ll y):x(x),y(y){}
    ll operator * (const Point&a)const{return x*a.x+y*a.y;}
    ll operator ^ (const Point&a)const{return y*a.x-x*a.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);}
    bool operator < (const Point&a)const{return x==a.x?y<a.y:x<a.x;}
};
vector<Point>tmp[N<<2],c1[N<<2],c2[N<<2];
struct segtree
{
    void insert(int l,int r,int u,ll x,ll y,int z)
    {
        tmp[u].push_back(Point(x,y));
        if(z==r)
        {
            sort(tmp[u].begin(),tmp[u].end());
            for(int i=0;i<tmp[u].size();i++)
            {
                while(c1[u].size()>1&&((c1[u][c1[u].size()-1]-c1[u][c1[u].size()-2])^(tmp[u][i]-c1[u][c1[u].size()-1]))<=0)c1[u].pop_back();
                c1[u].push_back(tmp[u][i]);
                while(c2[u].size()>1&&((c2[u][c2[u].size()-1]-c2[u][c2[u].size()-2])^(tmp[u][i]-c2[u][c2[u].size()-1]))>=0)c2[u].pop_back();
                c2[u].push_back(tmp[u][i]);
            }
        }
        if(l==r)return ;
        int mid = (l+r)>>1;
        if(z<=mid)insert(l,mid,u<<1,x,y,z);
        else insert(mid+1,r,u<<1|1,x,y,z);
    }
    void query(int l,int r,int u,Point p,int ql,int qr)
    {
        if(l==ql&&r==qr)
        {
            if(p.y>=0)
            {
                int L = 1,R = c1[u].size()-1,as = 0;
                while(L<=R)
                {
                    int mid = (L+R)>>1;
                    if(p*c1[u][mid]>p*c1[u][mid-1])as=mid,L=mid+1;
                    else R=mid-1;
                }
                ans=max(ans,p*c1[u][as]);
            }else
            {
                int L = 1,R = c2[u].size()-1,as = 0;
                while(L<=R)
                {
                    int mid = (L+R)>>1;
                    if(p*c2[u][mid]>p*c2[u][mid-1])as=mid,L=mid+1;
                    else R=mid-1;
                }
                ans=max(ans,p*c2[u][as]);
            }
            return ;
        }
        int mid = (l+r)>>1;
        if(qr<=mid)query(l,mid,u<<1,p,ql,qr);
        else if(ql>mid)query(mid+1,r,u<<1|1,p,ql,qr);
        else query(l,mid,u<<1,p,ql,mid),query(mid+1,r,u<<1|1,p,mid+1,qr);
    }
}tr;
int main()
{
    scanf("%d%s",&n,s0);
    for(int x,y,l,r,i=1;i<=n;i++)
    {
        scanf("%s%d%d",s,&x,&y);
        if(s0[0]!='E')x^=ans,y^=ans;
        if(s[0]=='A')
        {
            tot++;
            tr.insert(1,n,1,x,y,tot);
        }else
        {
            scanf("%d%d",&l,&r);
            if(s0[0]!='E')l^=ans,r^=ans;
            ans=-inf;
            tr.query(1,n,1,Point(x,y),l,r);
            printf("%lld
",ans);
            ans&=0x7fffffff;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10365037.html