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. Extjs4处理后台json数据中日期和时间的方法

    当ASP.NET后台使用JavaScriptSerializer这个组件将对象序列化为json,或者使用ScriptMethod特性的json [ScriptMethod(ResponseFormat ...

  2. jquery完成界面无刷新加载登陆注册

    昨天公司说官网的登陆注册每次要跳转到另一个界面,能不能做一个简单的,在界面弹出一个框框登陆,我想了想做了这么一个案例,大家来看看成不成 贴上代码,实现了在同一个弹出窗上加载了登陆注册功能!可自由点击! ...

  3. 【RabbitMQ】1、RabbitMQ的几种典型使用场景

    RabbitMQ主页:https://www.rabbitmq.com/ AMQP AMQP协议是一个高级抽象层消息通信协议,RabbitMQ是AMQP协议的实现.它主要包括以下组件: 1.Serve ...

  4. HDU5840(SummerTrainingDay08-B 树链剖分+分块)

    This world need more Zhu Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  5. JavaScript--DOM进阶(20)

    // DOM自身存在很多类型,在上一章中有介绍,比如Element类型:表示的是元素节点;再比如Text类型;表示的是文本节点; 一 DOM类型 类型名 说明 Node 表示所有类型值的统一接口,IE ...

  6. 【代码笔记】iOS-TableViewOfTwoSecton

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController ...

  7. equals 与 == 的区别

    equals 是 用来比较二个对象内容是否相等. == 是用来比较二个对象的内存是否相等. public void testString(){ String s1="123"; S ...

  8. JQuery 节点监听

    DOMSubtreeModified: 在DOM结构发生任何变化的时候.这个事件在其他事件触发后都会触发: $(".attr_box").bind("DOMSubtree ...

  9. vue Element-UI 分页使用(1)

    最近在使用Element-UI这套框架配合Vue来写前端页面.在用Element-UI来制作表格的时候,遇到了一些小问题,记录方便学习. 其中两个事件是关于切换当前页和切换显示的列表条数的.另外的属性 ...

  10. AngularJS单页面路由配置恩,理解了就很简单啦

    利用route实现单页面跳转功能 利用angularJS开发流程 1)配置好angularJS开发环境 2)利用 yo angular projectname创建项目目录 3)删除掉系统自动生成的一些 ...