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. Windows操作系统下Redis服务安装图文详解

    Redis下载地址:https://github.com/MSOpenTech/redis/releases 下载msi格式的安装文件. 1.运行安装程序,单击next按钮. 2.勾选接受许可协议中的 ...

  2. #if defined 和 #if ! defined 的用法

    背景:MFC初学,头文件中有#if !defined(AFX_HELLOMFC_H__706D36F5_2F1B_40AC_8BE9_0BD6A1D7BBDE__INCLUDED_)#define A ...

  3. SQL Server复制入门(二)----复制的几种模式

    简介 本系列文章的上一篇对复制是什么做了一个概述.本篇文章根据发布服务器,分发服务器和订阅服务器的组织方式和复制类型来讲述常用复制的几种模式. 模式的选择 选择复制的模式取决于多个方面.首先需要考虑具 ...

  4. Docker学习链接

    Docker安装篇 1>.Windows Docker 安装

  5. Java面试题—初级(9)

    139. Java中的泛型是什么 ? 使用泛型的好处是什么? 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数. 好处: 1.类型安全,提供编译期 ...

  6. SpingBoot —— RestTemplate的配置

    背景:最近工作上搭建了一个中间系统,采用了RestTemplate框架调用第三系统restful接口,调用方采用轮询的方式调用本系统的相关接口,期间多次出现堆内存溢出,系统假死,通用java自带的ja ...

  7. 小程序 波浪进度球 wave

    直接上代码: //index.js //获取应用实例 const app = getApp() var wave = function (ctx, oRange){ var tid; //oRange ...

  8. C# 如何防止重放攻击

    重放攻击 重放攻击是指黑客通过抓包的方式,得到客户端的请求数据及请求连接,重复的向服务器发送请求的行为. 比如你有一个 “购买” 的操作,当你点击购买按钮时,向服务器发送购买的请求.而这时黑客对你的请 ...

  9. Asp Url汉字乱码的问题

    1.js <a target="_blank" href="/asp/download.asp?File=' + escape(item.FileName) + ' ...

  10. MySql UNIX_TIMESTAMP和FROM_UNIXTIME函数讲解

    MySql UNIX_TIMESTAMP和FROM_UNIXTIME函数讲解 by:授客 QQ:1033553122 1. unix_timestamp(date)将时间转换为时间戳,如果参数为空,则 ...