zoukankan      html  css  js  c++  java
  • BZOJ3533:[SDOI2014]向量集(线段树,三分,凸包)

    Description

    维护一个向量集合,在线支持以下操作:
    "A x y (|x|,|y| < =10^8)":加入向量(x,y);
    " Q x y l r (|x|,|y| < =10^8,1 < =L < =R < =T,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。
    集合初始时为空。

    Input

    输入的第一行包含整数N和字符s,分别表示操作数和数据类别;
    接下来N行,每行一个操作,格式如上所述。
    请注意s≠'E'时,输入中的所有整数都经过了加密。你可以使用以下程序
    得到原始输入:
    inline int decode (int x long long lastans) {
         return x ^ (lastans & Ox7fffffff);
    }
    其中x为程序读入的数,lastans为之前最后一次询问的答案。在第一次询问之前,lastans=0。

    注:向量(x,y)和(z,W)的点积定义为xz+yw。

    Output

    对每个Q操作,输出一个整数表示答案。

    Sample Input

    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

    Sample Output

    13
    17
    17

    解释:解密之后的输入为
    6 E
    A 3 2
    Q 1 5 1 1
    A 2 3
    A 1 4
    Q 1 5 1 2
    Q 4 3 2 3

    HINT

    1 < =N < =4×10^5

    Solution

    设查询的点为$(a,b)$,那么我们需要在当前平面上找一个点$(x,y)$,使得$ax+by=c$的$c$最大化。

    把式子化一下为$y=-frac{a}{b}x+frac{c}{b}$。

    也就是斜率固定,我们要最大化$c$。比较显然的是这条直线肯定是在凸包上取到答案,现在的问题是怎么维护这个凸包。

    可以发现因为我们只需要点积的最大值,并不需要凸包的具体形态,所以我们可以开一颗线段树,每个节点维护对应区间的凸包,查询时把区间对应到线段树上的$log$个区间然后取$max$就好了。

    现在的问题是怎么修改。如果每次修改都重构线段树节点上的凸包的话,一次修改是$nlogn$的。

    不过我们发现可以不用一次修改所有的节点,线段树上的一个区间,会被用到当且仅当这个区间内的点已经全被插入了。这样一次修改的复杂度就是均摊$logn$的了,复杂度证明还是比较显然的……

    当$b>0$时,截距越大,$c$越大,我们在上凸壳上三分。

    当$b<0$时,截距越小,$c$越大,我们在下凸壳上三分。

    Code

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<vector>
      5 #include<cmath>
      6 #include<algorithm>
      7 #define N (400009) 
      8 #define LL long long
      9 using namespace std;
     10 
     11 struct Vector
     12 {
     13     LL x,y;
     14     Vector(double xx=0,double yy=0)
     15     {
     16         x=xx; y=yy;
     17     }
     18     bool operator < (const Vector &a) const
     19     {
     20         return x==a.x?y<a.y:x<a.x;
     21     }
     22 }a[N],P[N];
     23 typedef Vector Point;
     24 
     25 int n,x,y,l,r,cnt;
     26 LL ans;
     27 char s[2],opt[2];
     28 vector<Point>U[N<<2],D[N<<2];
     29 
     30 Vector operator - (Vector a,Vector b) {return Vector(a.x-b.x,a.y-b.y);}
     31 LL Cross(Vector a,Vector b) {return a.x*b.y-a.y*b.x;}
     32 LL Dot(Vector a,Vector b) {return a.x*b.x+a.y*b.y;}
     33 
     34 void decode(int &x)
     35 {
     36     x=x^(ans&0x7fffffff);
     37 }
     38 
     39 void ConvexHull(int now,int l,int r)
     40 {
     41     for (int i=l; i<=r; ++i) a[i]=P[i];
     42     sort(a+l,a+r+1);
     43     int h=0;
     44     for (int i=l; i<=r; ++i)
     45     {
     46         while (h>1 && Cross(a[i]-U[now][h-2],U[now][h-1]-U[now][h-2])<=0)
     47             h--, U[now].pop_back();
     48         h++; U[now].push_back(a[i]);
     49     }
     50     h=0;
     51     for (int i=l; i<=r; ++i)
     52     {
     53         while (h>1 && Cross(a[i]-D[now][h-2],D[now][h-1]-D[now][h-2])>=0)
     54             h--, D[now].pop_back();
     55         h++; D[now].push_back(a[i]);
     56     }
     57 }
     58 
     59 void Update(int now,int l,int r,int x)
     60 {
     61     if (l==r)
     62     {
     63         U[now].push_back(P[x]);
     64         D[now].push_back(P[x]);
     65         return;
     66     }
     67     int mid=(l+r)>>1;
     68     if (x<=mid) Update(now<<1,l,mid,x);
     69     else Update(now<<1|1,mid+1,r,x);
     70     if (x==r) ConvexHull(now,l,r);
     71 }
     72 
     73 LL Query(int now,int l,int r,int l1,int r1)
     74 {
     75     if (l>r1 || r<l1) return -1e18;
     76     if (l1<=l && r<=r1)
     77     {
     78         if (y>0)
     79         {
     80             int L=0,R=U[now].size()-1;
     81             Point p=Point(x,y);
     82             if (L==R) return Dot(p,U[now][L]);
     83             else if (L+1==R) return max(Dot(p,U[now][L]),Dot(p,U[now][R]));
     84             while (R-L>=3)
     85             {
     86                 int lmid=L+(R-L+1)/3,rmid=L+(R-L+1)/3*2;
     87                 LL ans1=Dot(p,U[now][lmid]);
     88                 LL ans2=Dot(p,U[now][rmid]);
     89                 if (ans1>ans2) R=rmid;
     90                 else L=lmid;
     91             }
     92             return max(Dot(p,U[now][L]),max(Dot(p,U[now][R]),Dot(p,U[now][R-1])));
     93         }
     94         else
     95         {
     96             int L=0,R=D[now].size()-1;
     97             Point p=Point(x,y);
     98             while (R-L>=3)
     99             {
    100                 int lmid=L+(R-L+1)/3,rmid=L+(R-L+1)/3*2;
    101                 LL ans1=Dot(p,D[now][lmid]);
    102                 LL ans2=Dot(p,D[now][rmid]);
    103                 if (ans1>ans2) R=rmid;
    104                 else L=lmid;
    105             }
    106             return max(Dot(p,D[now][L]),max(Dot(p,D[now][R]),Dot(p,D[now][R-1])));
    107         }
    108     }
    109     int mid=(l+r)>>1;
    110     return max(Query(now<<1,l,mid,l1,r1),Query(now<<1|1,mid+1,r,l1,r1));
    111 }
    112 
    113 int main()
    114 {
    115     scanf("%d%s",&n,s);
    116     for (int i=1; i<=n; ++i)
    117     {
    118         scanf("%s",opt);
    119         if (opt[0]=='A')
    120         {
    121             scanf("%d%d",&x,&y);
    122             if (s[0]!='E') decode(x), decode(y);
    123             P[++cnt]=Point(x,y);
    124             Update(1,1,n,cnt);
    125         }
    126         else
    127         {
    128             scanf("%d%d%d%d",&x,&y,&l,&r);
    129             if (s[0]!='E') decode(x), decode(y), decode(l), decode(r);
    130             ans=Query(1,1,n,l,r);
    131             printf("%lld
    ",ans);
    132         }
    133     }
    134 }
  • 相关阅读:
    “耐撕”团队 2016.3.25 站立会议
    “耐撕”团队 2016.03.24 站立会议
    “耐撕”团队 2016.3.22 站立会议
    windows环境下的git安装及使用
    词频统计(三)
    第二周作业
    Unity之GUI控件
    Lua的协同程序(coroutine)
    Lua与C++的交互
    Lua的元方法__newindex元方法
  • 原文地址:https://www.cnblogs.com/refun/p/10384645.html
Copyright © 2011-2022 走看看