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

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#define N (400009)
#define LL long long
using namespace std; struct Vector
{
LL x,y;
Vector(double xx=,double yy=)
{
x=xx; y=yy;
}
bool operator < (const Vector &a) const
{
return x==a.x?y<a.y:x<a.x;
}
}a[N],P[N];
typedef Vector Point; int n,x,y,l,r,cnt;
LL ans;
char s[],opt[];
vector<Point>U[N<<],D[N<<]; Vector operator - (Vector a,Vector b) {return Vector(a.x-b.x,a.y-b.y);}
LL Cross(Vector a,Vector b) {return a.x*b.y-a.y*b.x;}
LL Dot(Vector a,Vector b) {return a.x*b.x+a.y*b.y;} void decode(int &x)
{
x=x^(ans&0x7fffffff);
} void ConvexHull(int now,int l,int r)
{
for (int i=l; i<=r; ++i) a[i]=P[i];
sort(a+l,a+r+);
int h=;
for (int i=l; i<=r; ++i)
{
while (h> && Cross(a[i]-U[now][h-],U[now][h-]-U[now][h-])<=)
h--, U[now].pop_back();
h++; U[now].push_back(a[i]);
}
h=;
for (int i=l; i<=r; ++i)
{
while (h> && Cross(a[i]-D[now][h-],D[now][h-]-D[now][h-])>=)
h--, D[now].pop_back();
h++; D[now].push_back(a[i]);
}
} void Update(int now,int l,int r,int x)
{
if (l==r)
{
U[now].push_back(P[x]);
D[now].push_back(P[x]);
return;
}
int mid=(l+r)>>;
if (x<=mid) Update(now<<,l,mid,x);
else Update(now<<|,mid+,r,x);
if (x==r) ConvexHull(now,l,r);
} LL Query(int now,int l,int r,int l1,int r1)
{
if (l>r1 || r<l1) return -1e18;
if (l1<=l && r<=r1)
{
if (y>)
{
int L=,R=U[now].size()-;
Point p=Point(x,y);
if (L==R) return Dot(p,U[now][L]);
else if (L+==R) return max(Dot(p,U[now][L]),Dot(p,U[now][R]));
while (R-L>=)
{
int lmid=L+(R-L+)/,rmid=L+(R-L+)/*;
LL ans1=Dot(p,U[now][lmid]);
LL ans2=Dot(p,U[now][rmid]);
if (ans1>ans2) R=rmid;
else L=lmid;
}
return max(Dot(p,U[now][L]),max(Dot(p,U[now][R]),Dot(p,U[now][R-])));
}
else
{
int L=,R=D[now].size()-;
Point p=Point(x,y);
while (R-L>=)
{
int lmid=L+(R-L+)/,rmid=L+(R-L+)/*;
LL ans1=Dot(p,D[now][lmid]);
LL ans2=Dot(p,D[now][rmid]);
if (ans1>ans2) R=rmid;
else L=lmid;
}
return max(Dot(p,D[now][L]),max(Dot(p,D[now][R]),Dot(p,D[now][R-])));
}
}
int mid=(l+r)>>;
return max(Query(now<<,l,mid,l1,r1),Query(now<<|,mid+,r,l1,r1));
} int main()
{
scanf("%d%s",&n,s);
for (int i=; i<=n; ++i)
{
scanf("%s",opt);
if (opt[]=='A')
{
scanf("%d%d",&x,&y);
if (s[]!='E') decode(x), decode(y);
P[++cnt]=Point(x,y);
Update(,,n,cnt);
}
else
{
scanf("%d%d%d%d",&x,&y,&l,&r);
if (s[]!='E') decode(x), decode(y), decode(l), decode(r);
ans=Query(,,n,l,r);
printf("%lld\n",ans);
}
}
}

BZOJ3533:[SDOI2014]向量集(线段树,三分,凸包)的更多相关文章

  1. BZOJ 3533: [Sdoi2014]向量集( 线段树 + 三分 )

    答案一定是在凸壳上的(y>0上凸壳, y<0下凸壳). 线段树维护, 至多N次询问, 每次询问影响O(logN)数量级的线段树结点, 每个结点O(logN)暴力建凸壳, 然后O(logN) ...

  2. bzoj 3533: [Sdoi2014]向量集 线段树维护凸包

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3533 题解: 首先我们把这些向量都平移到原点.这样我们就发现: 对于每次询问所得到的an ...

  3. bzoj 3533 [Sdoi2014]向量集 线段树+凸包+三分(+动态开数组) 好题

    题目大意 维护一个向量集合,在线支持以下操作: "A x y (|x|,|y| < =10^8)":加入向量(x,y); "Q x y l r (|x|,|y| & ...

  4. 【bzoj3533】[Sdoi2014]向量集 线段树+STL-vector维护凸包

    题目描述 维护一个向量集合,在线支持以下操作:"A x y (|x|,|y| < =10^8)":加入向量(x,y);"Q x y l r (|x|,|y| < ...

  5. BZOJ3533 [Sdoi2014]向量集 【线段树 + 凸包 + 三分】

    题目链接 BZOJ3533 题解 我们设询问的向量为\((x_0,y_0)\),参与乘积的向量为\((x,y)\) 则有 \[ \begin{aligned} ans &= x_0x + y_ ...

  6. [SDOI2014][BZOJ3533] 向量集 [线段树+凸包]

    题面 BZOJ传送门 思路 首先当然是推式子 对于一个询问点$(x_0,y_0$和给定向量$(x_1,y_1)$来说,点积这么表达: $A=x_0x_1+y_0y_1$ 首先肯定是考虑大小关系:$x_ ...

  7. bzoj3533: [Sdoi2014]向量集

    Description 维护一个向量集合,在线支持以下操作:"A x y (|x|,|y| < =10^8)":加入向量(x,y);" Q x y l r (|x| ...

  8. 2019.02.26 bzoj4311: 向量(线段树分治+凸包)

    传送门 题意: 支持插入一个向量,删去某一个现有的向量,查询现有的所有向量与给出的一个向量的点积的最大值. 思路: 考虑线段树分治. 先对于每个向量处理出其有效时间放到线段树上面,然后考虑查询:对于两 ...

  9. 【BZOJ4311】向量(线段树分治,斜率优化)

    [BZOJ4311]向量(线段树分治,斜率优化) 题面 BZOJ 题解 先考虑对于给定的向量集,如何求解和当前向量的最大内积. 设当前向量\((x,y)\),有两个不同的向量\((u1,v1),(u2 ...

随机推荐

  1. ADO.NET 【实体类】【数据访问类】

    认识分层结构,分层式结构是最常见,也是最重要的一种结构. 三层架构(3-tier architecture) 界面层(User Interface layer) 主要对用户的请求接受,以及数据的返回, ...

  2. JavaSE Collections类 , Iterator迭代器 , 增强for循环

    Collections 它是集合的工具类,为集合体系扩展了一些其他的方法.类中都是静态的方法,可以使用类名直接调用. 可变参数 在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类 ...

  3. Java虚拟机--内存模型与线程

    Java虚拟机--内存模型与线程 高速缓存:处理器要与内存交互,如读取.存储运算结果,而计算机的存储设备和处理器的运算速度差异巨大,所以加入一层读写速度和处理器接近的高速缓存来作为内存和处理器之间的缓 ...

  4. 使用commons-pool2实现FTP连接池

    ​ GitHub : https://github.com/jayknoxqu/ftp-pool 一. 连接池概述 ​ 频繁的建立和关闭连接,会极大的降低系统的性能,而连接池会在初始化的时候会创建一定 ...

  5. 【Winform系列】Winform控件DataGridView添加数据的几种方式

    1:直接添加 在控件中设置好每列的名称 例如: DataGridViewRow row = new DataGridViewRow(); int j = dgv.Rows.Add(row); dgv. ...

  6. Java - "JUC" Semaphore源码分析

    Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例 Semaphore简介 Semaphore是一个计数信号量,它的本质是一个"共享锁". 信号量维护了 ...

  7. python并发编程-线程和锁

    什么是线程 进程:资源分配单位 线程:cpu执行单位(实体),每一个py文件中就是一个进程,一个进程中至少有一个线程 线程的两种创建方式: from multiprocessing import Pr ...

  8. Object.assign简单总结

    定义 Object.assign方法用来将源对象source的所有可枚举属性复制到目标对象target.至少需要两个对象作为参数,第一个参数为源对象,后面的均为目标对象.(以下用source代指源对象 ...

  9. FineBI表单如何更新

    FineBI表单如何更新 1. 描述Cube单表更新,是指在某个业务包上面设置定时更新,在某个固定的时间点对某个的业务包中的特定表进行数据更新,部分更新分为两种,全量更新和增量更新,因而在更新策略上则 ...

  10. 【CLR Via C#】15 枚举类型与位类型

    1.基础 枚举类型(enumerated types)定义了一组“符号名称/值”配对. 枚举类型是值类型,每个枚举类型都是从System.Enum派生的,而System.Enum又是从System.V ...