题目链接

BZOJ3533

题解

我们设询问的向量为\((x_0,y_0)\),参与乘积的向量为\((x,y)\)

则有

\[\begin{aligned}
ans &= x_0x + y_0y \\
y &= -\frac{x_0}{y_0}x + \frac{ans}{y_0} \\
\end{aligned}
\]

所以向量集里的向量实际上可以对应到平面上一组点,我们用一个斜率固定的直线去经过这些点,使得斜率最大或最小

当\(y_0 > 0\)时,要求截距最大

当\(y_0 < 0\)时,要求截距最小

当\(y_0 = 0\)时,只用讨论\(x\)

这样看来,能产生贡献的点,一定是凸包上的点,前者是上凸包,后者是下凸包,\(y_0 = 0\)要求\(x\)的极值,上下凸包都可

所以我们的问题就转化为了如何快速求出区间的凸包

由于是求最优解,我们并不需要每次都对整个区间建一个凸包,分成若干个小凸包合并答案也是可以的

所以我们可以线段树维护区间凸包,当一个区间满的时候再建立凸包即可

由于每一层都是\(n\)个位置,所以总的复杂度是\(O(nlog^2n)\)的

询问的时候在每个凸包上三分,也是\(O(nlog^2n)\)的

有几点要注意的:

①INF要足够大

②整型三分的姿势

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cmath>
  6. #include<vector>
  7. #include<map>
  8. #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
  9. #define REP(i,n) for (int i = 1; i <= (n); i++)
  10. #define mp(a,b) make_pair<int,int>(a,b)
  11. #define cls(s) memset(s,0,sizeof(s))
  12. #define cp pair<int,int>
  13. #define LL long long int
  14. #define pb push_back
  15. #define ls (u << 1)
  16. #define rs (u << 1 | 1)
  17. using namespace std;
  18. const int maxn = 400005,maxm = 100005;
  19. const LL INF = 9223372036854775807ll;
  20. inline int read(){
  21. int out = 0,flag = 1; char c = getchar();
  22. while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
  23. while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
  24. return out * flag;
  25. }
  26. struct point{
  27. LL x,y;
  28. }p[maxn],t[maxn];
  29. inline point operator -(const point& a,const point& b){
  30. return (point){a.x - b.x,a.y - b.y};
  31. }
  32. inline point operator +(const point& a,const point& b){
  33. return (point){a.x + b.x,a.y + b.y};
  34. }
  35. inline LL cross(const point& a,const point& b){
  36. return a.x * b.y - a.y * b.x;
  37. }
  38. inline LL operator *(const point& a,const point& b){
  39. return a.x * b.x + a.y * b.y;
  40. }
  41. inline double slope(const point& a,const point& b){
  42. if (a.x == b.x) return INF;
  43. return 1.0 * (a.y - b.y) / (a.x - b.x);
  44. }
  45. inline bool operator <(const point& a,const point& b){
  46. return a.x == b.x ? a.y < b.y : a.x < b.x;
  47. }
  48. inline bool operator ==(const point& a,const point& b){
  49. return a.x == b.x && a.y == b.y;
  50. }
  51. int n,now; char S;
  52. LL lans;
  53. inline int decode (int x ,LL lastans) {
  54. return S == 'E' ? x : (x ^ (lastans & 0x7fffffff));
  55. }
  56. vector<point> Tu[maxn << 2],Td[maxn << 2];
  57. int top[maxn << 2],Top[maxn << 2];
  58. point st[maxn];
  59. void build(int u,int l,int r){
  60. int N = 0;
  61. for (int i = l; i <= r; i++) t[++N] = p[i];
  62. sort(t + 1,t + 1 + N);
  63. top[u] = -1;
  64. for (int i = 1; i <= N; i++){
  65. if (i > 1 && t[i] == t[i - 1]) continue;
  66. while (top[u] > 0 && cross(st[top[u]] - st[top[u] - 1],t[i] - st[top[u]]) >= 0)
  67. top[u]--;
  68. st[++top[u]] = t[i];
  69. }
  70. for (int i = 0; i <= top[u]; i++) Tu[u].pb(st[i]);
  71. Top[u] = -1;
  72. for (int i = 1; i <= N; i++){
  73. if (i > 1 && t[i] == t[i - 1]) continue;
  74. while (Top[u] > 0 && cross(st[Top[u]] - st[Top[u] - 1],t[i] - st[Top[u]]) <= 0)
  75. Top[u]--;
  76. st[++Top[u]] = t[i];
  77. }
  78. for (int i = 0; i <= Top[u]; i++) Td[u].pb(st[i]);
  79. }
  80. void insert(int u,int l,int r){
  81. if (l == r){Tu[u].pb(p[now]); Td[u].pb(p[now]); top[u] = Top[u] = 0; return;}
  82. if (now == r) build(u,l,r);
  83. int mid = l + r >> 1;
  84. if (mid >= now) insert(ls,l,mid);
  85. else insert(rs,mid + 1,r);
  86. }
  87. LL qmax(int u,point P){
  88. if (P.y >= 0){
  89. int l = 0,r = top[u],lmid,rmid;
  90. while (r - l >= 3){
  91. lmid = (l + l + r) / 3;
  92. rmid = (r + l + r) / 3;
  93. if (P * Tu[u][lmid] <= P * Tu[u][rmid]) l = lmid;
  94. else r = rmid;
  95. }
  96. LL ans = -INF;
  97. for (int i = l; i <= r; i++) ans = max(ans,P * Tu[u][i]);
  98. return ans;
  99. }
  100. else {
  101. int l = 0,r = Top[u],lmid,rmid;
  102. while (r - l >= 3){
  103. lmid = (l + l + r) / 3;
  104. rmid = (r + l + r) / 3;
  105. if (P * Td[u][lmid] <= P * Td[u][rmid]) l = lmid;
  106. else r = rmid;
  107. }
  108. LL ans = -INF;
  109. for (int i = l; i <= r; i++) ans = max(ans,P * Td[u][i]);
  110. return ans;
  111. }
  112. }
  113. LL query(int u,int l,int r,int L,int R,point a){
  114. if (l >= L && r <= R) return qmax(u,a);
  115. int mid = l + r >> 1;
  116. if (mid >= R) return query(ls,l,mid,L,R,a);
  117. if (mid < L) return query(rs,mid + 1,r,L,R,a);
  118. return max(query(ls,l,mid,L,R,a),query(rs,mid + 1,r,L,R,a));
  119. }
  120. int main(){
  121. n = read(); scanf("%c",&S);
  122. char opt; int x,y,l,r;
  123. for (int i = 1; i <= n; i++){
  124. opt = getchar(); while (opt != 'A' && opt != 'Q') opt = getchar();
  125. x = decode(read(),lans);
  126. y = decode(read(),lans);
  127. if (opt == 'A'){
  128. p[++now] = (point){x,y};
  129. insert(1,1,n);
  130. }
  131. else {
  132. l = decode(read(),lans);
  133. r = decode(read(),lans);
  134. lans = query(1,1,n,l,r,(point){x,y});
  135. printf("%lld\n",lans);
  136. }
  137. }
  138. return 0;
  139. }

BZOJ3533 [Sdoi2014]向量集 【线段树 + 凸包 + 三分】的更多相关文章

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

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

  2. BZOJ3533:[SDOI2014]向量集(线段树,三分,凸包)

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

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

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

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

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

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

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

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

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

  7. bzoj 4311 向量 时间线建线段树+凸包+三分

    题目大意 你要维护一个向量集合,支持以下操作: 1.插入一个向量(x,y) 2.删除插入的第i个向量 3.查询当前集合与(x,y)点积的最大值是多少.如果当前是空集输出0 分析 按时间线建线段树 大致 ...

  8. bzoj3533: [Sdoi2014]向量集

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

  9. BZOJ4311 向量(线段树分治+三分)

    由点积的几何意义(即投影)可以发现答案一定在凸壳上,并且投影的变化是一个单峰函数,可以三分.现在需要处理的只有删除操作,线段树分治即可. #include<iostream> #inclu ...

随机推荐

  1. thinkphp5数据库导入Excel表格

    $data=$order_info; //$data 你要下载谁 就去查谁 // $data= Db::name('order_info') // ->field('consignee,tel, ...

  2. 商城项目:商品列表ajax加载,ajax加入购物车--五张表的联合查询

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ProductLists.a ...

  3. CAS解扰小结

    1.每个ts数据包由:1.包头 2.包数据 包头有个字段 PID ,该字段指示包数据的类型.比如说: PID 为 0x0000 包数据的类型就是 PAT表 PID 为 0x0001 包数据的类型就是 ...

  4. linux实验-基本指令1

    1.root帐号登录,查看/tmp目录,如果/tmp目录下没有子目录myshare,则建立该目录. 2.创建帐号testuser. 3.把myshare目录及其目录下的所有文件和子目录的拥有者该为te ...

  5. [Python 3.X]python练习笔记[2]-----用python实现七段数码管显示年月日

    #SevenDigitsDrawV2.py import turtle import time def drawGap(i):#绘制数码管间隔 turtle.penup() turtle.fd(i) ...

  6. 《python核心编程第二版》第4章习题

    4–1. Python 对象.与所有 Python 对象有关的三个属性是什么?请简单的

  7. VMware快照

    越来越多的人喜欢使用虚拟机来做实验,但是实验过程并不总是顺利的,所以我们就需要掌握虚拟机快照的使用方法,个人建议的顺序为: 1 在虚拟机打开之前,点击“虚拟机”--"快照"--&q ...

  8. Django数据模型--表关系(一对多)

    一.一对一关系 使用方法:models.ForeignKey(要关联的模型) 举例说明:年级.教师和学生 from django.db import models class Grade(models ...

  9. python中logging的常用方法

    logging常用 # -*- coding:utf-8 -*- __author__ = "lgj" import os import sys import time impor ...

  10. linux常用命令补充详细

    1.ls命令 就是list的缩写,通过ls 命令不仅可以查看linux文件夹包含的文件,而且可以查看文件权限(包括目录.文件夹.文件权限)查看目录信息等等 常用参数搭配: ls -a 列出目录所有文 ...