[SDOI2014]向量集

Posted by Dispwnl on January 23, 2019

题目

题目描述

维护一个向量集合,在线支持以下操作:

  • “A x y $(\vert x\vert ,\vert y\vert \le 10^8)$”:加入向量(x,y);
  • ” Q x y l r $(\vert x\vert,\vert y\vert \le 10^8,1 \le L \le R \le T)$,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。

集合初始时为空。

输入输出格式

输入格式:

输入的第一行包含整数N和字符s,分别表示操作数和数据类别; 接下来N行,每行一个操作,格式如上所述。

请注意s≠’E’时,输入中的所有整数都经过了加密。你可以使用以下程序得到原始输入:

inline int decode (int x long long lastans) {
return x ^ (lastans & 0x7fffffff); }

其中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

说明

1 < =N < =4*10^5

题解

看到向量,就想到构建凸包(大雾

因为要求点积的最大值,设点积为$t$,则有$t=xx’+yy’$($(x,y)$为询问向量)

移一下项,同除$y$,$y’=\frac{-xx’+t}{y}$

这就是一个关于$x’,y’$的一次函数,要求的是$t$的最大值,所以分$y$的正负性讨论一下在上凸壳还是在下凸壳求,在上下凸壳上三分一下就行

然后y你分正负讨论一下发现还是可以直接比较点积

癌怎么维护凸包啊……

这太简单了写个线段树套平衡树维护动态凸包就行了

因为查询的区间肯定都是满区间,所以等一个区间满了的时候一次性构造凸包就行了

时间复杂度是$O(n\log^2n)$的

因为凸包的比较函数写错了调了一下午+一晚上……

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<vector>
# include<cmath>
# include<algorithm>
# define tl s[k].l
# define tr s[k].r
# define mid (l+r>>1)
# define LL long long
using namespace std;
const int MAX=4e5+5;
struct Point{
    int x,y;
    Point(int X=0,int Y=0) {x=X,y=Y;}
    bool operator< (const Point &a)
    const{
        if(x!=a.x) return x<a.x;
        return y<a.y;
    }
}_P[MAX],H;
struct p{
    int l,r,Top,cnt,str,_L;
}s[MAX<<2];
int n,rt,tot,cnt,_cnt,__cnt;
LL ans;
int st[MAX<<4];
bool FL;
vector<Point> __P[MAX<<3];
int read(LL ans=0)
{
    int x=0,fl=1;
    char ch=getchar();
    for(;!isdigit(ch);fl=(ch=='-')?-1:1,ch=getchar());
    for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
    x=x*fl;
    if(FL) x=x^(ans&0x7fffffff);
    return x;
}
Point operator- (Point x,Point y) {return Point(x.x-y.x,x.y-y.y);}
LL Cross(Point x,Point y) {return 1ll*x.x*y.y-1ll*x.y*y.x;}
LL Dot(Point x,Point y) {return 1ll*x.x*y.x+1ll*x.y*y.y;}
LL Cmp(Point a,Point b,Point c) {return Cross(b-a,c-a);}
bool cmp(Point a,Point b)
{
    if(!Cmp(H,a,b)) return a<b;
    return Cmp(H,a,b)>0;
}
char Read()
{
    char ch=getchar();
    for(;!isalpha(ch);ch=getchar());
    return ch;
}
void GET_HULL(int k)
{
    if(s[k].cnt==1) return;
    sort(__P[k].begin(),__P[k].end()),H=__P[k][0],st[s[k].Top=++_cnt]=0,sort(__P[k].begin()+1,__P[k].end(),cmp),s[k].str=_cnt;
    for(int i=1;i<s[k].cnt;++i)
      {
      	while(s[k].Top>_cnt&&Cross(__P[k][st[s[k].Top]]-__P[k][st[s[k].Top-1]],__P[k][i]-__P[k][st[s[k].Top]])<=0) --s[k].Top;
      	st[++s[k].Top]=i;
      }
    _cnt=s[k].Top,s[k]._L=s[k].Top;
    for(int i=s[k].str;i<s[k].Top;++i)
      if(__P[k][st[i]].x>=__P[k][st[i+1]].x) {s[k]._L=i;break;}
    ++_cnt,st[++s[k].Top]=0;
}
LL GET_B(Point A,Point B) {return Dot(A,B);}
LL GET_UP(int k,Point A)
{
    if(s[k].cnt==1) return Dot(__P[k][0],A);
    int l=s[k]._L,r=s[k].Top;
    while(l+3<=r)
    {
        int midl=(l+r>>1),midr=(midl+r>>1);
        if(GET_B(A,__P[k][st[midl]])>GET_B(A,__P[k][st[midr]])) r=midr;
        else l=midl;
    }
    LL Ans=-1e18;
    for(int i=l;i<=r;++i)
      Ans=max(Ans,Dot(__P[k][st[i]],A));
    return Ans;
}
LL GET_DOWN(int k,Point A)
{
    if(s[k].cnt==1) return Dot(__P[k][0],A);
    int l=s[k].str,r=s[k]._L;
    while(l+3<=r)
    {
        int midl=l+r>>1,midr=midl+r>>1;
        if(GET_B(A,__P[k][st[midl]])>GET_B(A,__P[k][st[midr]])) r=midr;
        else l=midl;
    }
    LL Ans=-1e18;
    for(int i=l;i<=r;++i)
      Ans=max(Ans,Dot(__P[k][st[i]],A));
    return Ans;
}
LL ask(int l,int r,int k,int L,int R,Point A)
{
    if(r<L||R<l) return -1e18;
    if(l>=L&&r<=R) return max(GET_UP(k,A),GET_DOWN(k,A));
    if(R<=mid) return ask(l,mid,tl,L,R,A);
    if(L>mid) return ask(mid+1,r,tr,L,R,A);
    return max(ask(l,mid,tl,L,R,A),ask(mid+1,r,tr,L,R,A));
}
void change(int l,int r,int &k,int x)
{
    if(!k) k=++tot;
    __P[k].push_back(_P[x]),++s[k].cnt;
    if(s[k].cnt==r-l+1) GET_HULL(k);
    if(l==r) return;
    if(x<=mid) change(l,mid,tl,x);
    else change(mid+1,r,tr,x);
}
int main()
{
    n=read(),FL=(Read()=='E'?0:1);
    for(int i=1,x,y,l,r,L=0;i<=n;++i)
      {
      	char A=Read();
      	x=read(ans),y=read(ans);
      	if(A=='Q') l=read(ans),r=read(ans),printf("%lld\n",ans=ask(1,n,rt,l,r,Point(x,y)));
      	else if(A=='A') _P[++L]=Point(x,y),change(1,n,rt,L);
      }
    return 0;
}