向量集

向量集

题目描述:扔个传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3533

题解

首先,可以证明答案一定在凸壳上。
若y>0,则答案在上凸壳上找到,若y<0,则在下凸壳上找到。
所以,我们需要分别维护区间的上下凸壳,也就是一个凸包。
这里可以利用线段树进行维护。
显然,一个线段树上的区间可以被查询到,当且仅当这个区间的右端点已经被更新。
因此,每加入一个点,就对满的区间求凸包。
查询操作只需在凸包上进行三分即可。

代码

#include<iostream> 
#include<cstdio> 
#include<cstdlib> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<algorithm>
#define ll long long
#define N 400005 
#define inf 1e15
using namespace std;
int n,m,cnt,tot,flag;ll la;

struct node{
  ll x,y;
  bool operator<(const node &p)
  const{return x<p.x||(x==p.x&&y<p.y);}
  node operator-(const node &p)
  const{return (node){x-p.x,y-p.y};}
  ll operator*(const node &p)
  const{return x*p.x+y*p.y;}
  ll operator^(const node &p)
  const{return x*p.y-y*p.x;}
}s[N*40],p[N],q[N*2],po[N];

struct point{
  int L1,R1,L2,R2;
  void build(int x,int y)
  {
    int len=y-x+1,top=0;
    for(int i=1;i<=len;i++)p[i]=po[x+i-1];
    sort(p+1,p+len+1);
    for(int i=1;i<=len;i++)
    {
      while(top&&(q[top]-q[top-1]^p[i]-q[top])<=0)top--;
      q[++top]=p[i];
    }
    int sum=top;
    for(int i=len;i;i--)
    {
      while(top>sum&&(q[top]-q[top-1]^p[i]-q[top])<=0)top--;
      q[++top]=p[i];
    }
    L1=tot+1;R1=L1+sum-1;L2=R1;R2=L1+top-1;
    for(int i=1;i<=top;i++)s[++tot]=q[i];
  }
  ll qry(int x,int y)
  {
    int l,r;ll res=-inf;node p=(node){x,y};
    if(y<0)l=L1,r=R1;
    else l=L2,r=R2;
    while(r-l>3)
    {
      int len=(r-l+1)/3,lx=l+len,rx=r-len;
      if(s[lx]*p>s[rx]*p)r=rx;
      else l=lx;
    }
    for(int i=l;i<=r;i++)res=max(res,p*s[i]);
    return res;
  }
}t[N*4];

class seg_tree
{
  public:
  void modify(int x,int l,int r,int des)
  {
    if(des==r)t[x].build(l,r);
    if(l==r)return;
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    if(des<=mid)modify(lc,l,mid,des);
    else modify(rc,mid+1,r,des);
  }
  ll qry(int x,int l,int r,int ql,int qr,int a,int b)
  {
    if(ql<=l&&r<=qr)return t[x].qry(a,b);
    int mid=l+r>>1,lc=x<<1,rc=lc+1;ll res=-inf;
    if(ql<=mid)res=max(res,qry(lc,l,mid,ql,qr,a,b));
    if(qr>mid)res=max(res,qry(rc,mid+1,r,ql,qr,a,b));
    return res;
  }
}T;

int get(int x)
{
  return x^(la&0x7fffffff); 
}

int main()
{
  int x,y,l,r;char ch;
  scanf("%d %c",&n,&ch);
  m=n;flag=ch!='E';
  while(m--)
  {
    scanf(" %c%d%d",&ch,&x,&y);
    if(flag)x=get(x),y=get(y);
    if(ch=='A')
    {
      po[++cnt]=(node){x,y};
      T.modify(1,1,n,cnt);
    }
    else
    {
      scanf("%d%d",&l,&r);
      if(flag)l=get(l),r=get(r);
      printf("%lld\n",la=T.qry(1,1,n,l,r,x,y));
    }
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值