bzoj 3533: [Sdoi2014]向量集 线段树维护凸包
题目大意:
题解:
首先我们把这些向量都平移到原点.这样我们就发现:
对于每次询问所得到的ans一定由凸包上的点做出贡献。
我们按照给出的询问点的纵坐标的正负做出划分:
若为正:那么对答案做出贡献的点一定在上凸壳上
若为负:那么对答案做出贡献的点一定在下凸壳上
所以我们可以分别考虑上下凸壳.不失一般性,我们假设纵坐标为正.
那么这时候答案肯定在上凸壳上
并且这个上凸壳上的所有点和询问点组成的答案一定是一个单峰函数
所以我们三分解决这个问题
那么现在的问题就是解决查询的是一个区间的问题了
首先我们发现,对于不同的区间的查询结果,合并时只需要去max即可
所以我们可以把询问的区间拆成若干个区间合并得到结果
所以我们用线段树维护即可.
但是合并凸包的复杂度是\(O(n)\),我们不可能每次插入一个点都更新
但是我们发现,对于每个区间,只有里面所有的点都被插入后才可能会被查询到
所以我们只在一个区间内所有的点都被插入后再合并左右子树的凸包即可.
复杂度?
每个点只会被合并\(logn\)次,每次查询是\(log^2n\)的
所以总复杂度是\(O(mlog^2n)\)
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline ll cat_max(const ll &a,const ll &b){return a>b ? a:b;}
inline ll cat_min(const ll &a,const ll &b){return a<b ? a:b;}
const ll maxn = 400010;
struct Point{
ll x,y;
Point(const ll &a=0,const ll &b=0){x=a;y=b;}
bool friend operator < (const Point &a,const Point &b){
return a.x == b.x ? a.y < b.y : a.x < b.x;
}
void print(){
printf("Point : (%lld,%lld)\n",x,y);
}
};
Point operator - (const Point &a,const Point &b){
return Point(a.x-b.x,a.y-b.y);
}
ll operator * (const Point &a,const Point &b){
return a.x*b.x + a.y*b.y;
}
ll cross(const Point &a,const Point &b){
return a.x*b.y - a.y*b.x;
}
struct SB{
int cmd,l,r,id;
Point p;
}op[maxn];
int nowpos;
inline void Unionu(const vector<Point> &a,const vector<Point> &b,vector<Point> &c){
c.clear();int m = 0,siza = a.size(),sizb = b.size(),i=0,j=0;
Point p;
while(i < siza || j < sizb){
if((i == siza) || ((j < sizb) && (b[j] < a[i]))) p = b[j++];
else p = a[i++];
while(m > 1 && cross(c[m-1] - c[m-2],p - c[m-1]) >= 0) -- m,c.pop_back();
m++;c.push_back(p);
}
}
inline void Uniond(const vector<Point> &a,const vector<Point> &b,vector<Point> &c){
c.clear();int m = 0,siza = a.size(),sizb = b.size(),i=0,j=0;
Point p;
while(i < siza || j < sizb){
if((i == siza) || ((j < sizb) && (b[j] < a[i]))) p = b[j++];
else p = a[i++];
while(m > 1 && cross(c[m-1] - c[m-2],p - c[m-1]) <= 0) -- m,c.pop_back();
m++;c.push_back(p);
}
}
struct Node{
vector<Point>Tu,Td;
Node *ch[2];
}*null,*root;
inline void init(){
null = new Node();null->ch[0] = null->ch[1] = null;
null->Tu.clear();null->Td.clear();root = null;
}
inline Node* newNode(){
Node *p = new Node();p->ch[0] = p->ch[1] = null;
p->Tu.clear();p->Td.clear();return p;
}
void insert(Node* &p,int l,int r){
if(p == null) p = newNode();
if(l == r){
p->Tu.clear();p->Td.clear();
p->Tu.push_back(op[nowpos].p);
p->Td.push_back(op[nowpos].p);
return;
}
int mid = (l+r) >> 1;
if(op[nowpos].id <= mid) insert(p->ch[0],l,mid);
else insert(p->ch[1],mid+1,r);
if(op[nowpos].id == r){
Unionu(p->ch[0]->Tu,p->ch[1]->Tu,p->Tu);
Uniond(p->ch[0]->Td,p->ch[1]->Td,p->Td);
}return;
}
ll query(const vector<Point> &v){
int l = 0,r = v.size()-1;
while(l + 3 <= r){
int midx = (l+l+r)/3;
int midy = (l+r+r)/3;
if((v[midx]*op[nowpos].p) > (v[midy]*op[nowpos].p)) r = midy;
else l = midx;
}
ll ret = -(1LL<<60);
for(int i=l;i<=r;++i) ret = max(ret,v[i]*op[nowpos].p);
return ret;
}
ll queryu(Node *p,int l,int r){
if(op[nowpos].l <= l && r <= op[nowpos].r) return query(p->Tu);
int mid = (l+r) >> 1;
if(op[nowpos].r <= mid) return queryu(p->ch[0],l,mid);
if(op[nowpos].l > mid) return queryu(p->ch[1],mid+1,r);
return max(queryu(p->ch[0],l,mid),queryu(p->ch[1],mid+1,r));
}
ll queryd(Node *p,int l,int r){
if(op[nowpos].l <= l && r <= op[nowpos].r) return query(p->Td);
int mid = (l+r) >> 1;
if(op[nowpos].r <= mid) return queryd(p->ch[0],l,mid);
if(op[nowpos].l > mid) return queryd(p->ch[1],mid+1,r);
return max(queryd(p->ch[0],l,mid),queryd(p->ch[1],mid+1,r));
}
ll lastans = 0;
#define decode(x) (x = (x^(lastans & 0x7fffffff)))
int main(){
char ch;int cnt = 0;
int n;read(n);while(ch=getchar(),ch<'!');
bool e = true;if(ch == 'E') e = false;
for(int i=1;i<=n;++i){
while(ch=getchar(),ch<'!');op[i].cmd = ch == 'A';
if(op[i].cmd){
++cnt;read(op[i].p.x);read(op[i].p.y);
op[i].id = cnt;
}else{
read(op[i].p.x);read(op[i].p.y);
read(op[i].l);read(op[i].r);
}
}
for(int i=1;i<=n;++i){
if(op[i].cmd){
if(e) decode(op[i].p.x),decode(op[i].p.y);
nowpos = i;
insert(root,1,cnt);
}else{
if(e){
decode(op[i].p.x);decode(op[i].p.y);
decode(op[i].l);decode(op[i].r);
}
nowpos = i;
if(op[i].p.y > 0) lastans = queryu(root,1,cnt);
else lastans = queryd(root,1,cnt);
//lastans = max(queryd(root,1,cnt),queryu(root,1,cnt));
printf("%lld\n",lastans);
}
}
getchar();getchar();
return 0;
}
但貌似官方题解有更巧妙的做法...

bzoj 3533: [Sdoi2014]向量集 线段树维护凸包的更多相关文章
- BZOJ 3533: [Sdoi2014]向量集( 线段树 + 三分 )
答案一定是在凸壳上的(y>0上凸壳, y<0下凸壳). 线段树维护, 至多N次询问, 每次询问影响O(logN)数量级的线段树结点, 每个结点O(logN)暴力建凸壳, 然后O(logN) ...
- bzoj 3533 [Sdoi2014]向量集 线段树+凸包+三分(+动态开数组) 好题
题目大意 维护一个向量集合,在线支持以下操作: "A x y (|x|,|y| < =10^8)":加入向量(x,y); "Q x y l r (|x|,|y| & ...
- BZOJ3533:[SDOI2014]向量集(线段树,三分,凸包)
Description 维护一个向量集合,在线支持以下操作: "A x y (|x|,|y| < =10^8)":加入向量(x,y); " Q x y l r (| ...
- 【bzoj3533】[Sdoi2014]向量集 线段树+STL-vector维护凸包
题目描述 维护一个向量集合,在线支持以下操作:"A x y (|x|,|y| < =10^8)":加入向量(x,y);"Q x y l r (|x|,|y| < ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- BZOJ 3910 并查集+线段树合并
思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ...
- [SDOI2014][BZOJ3533] 向量集 [线段树+凸包]
题面 BZOJ传送门 思路 首先当然是推式子 对于一个询问点$(x_0,y_0$和给定向量$(x_1,y_1)$来说,点积这么表达: $A=x_0x_1+y_0y_1$ 首先肯定是考虑大小关系:$x_ ...
- YYHS-猜数字(并查集/线段树维护)
题目描述 LYK在玩猜数字游戏. 总共有n个互不相同的正整数,LYK每次猜一段区间的最小值.形如[li,ri]这段区间的数字的最小值一定等于xi. 我们总能构造出一种方案使得LY ...
- 【BZOJ】4311: 向量(线段树分治板子题)
题解 我们可以根据点积的定义,垂直于原点到给定点构成的直线作一条直线,从正无穷往下平移,第一个碰到的点就是答案 像什么,上凸壳哇 可是--动态维护上凸壳? 我们可以离线,计算每个点能造成贡献的一个询问 ...
随机推荐
- 【BZOJ3744】Gty的妹子序列 分块+树状数组
[BZOJ3744]Gty的妹子序列 Description 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzo ...
- 基于python实现简单web服务器
做web开发的你,真的熟悉web服务器处理机制吗? 分析请求数据 下面是一段原始的请求数据: b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8000\r\nConnectio ...
- 【python】-- json & pickle、xml、requests、hashlib、shelve、shutil、configparser、subprocess
json & pickle Python中用于序列化的两个模块 json 用于[字符串]和 [python基本数据类型] 间进行转换 pickle 用于[python特有的类型] ...
- [luogu4255]公主の#18文明游戏
[luogu4255]公主の#18文明游戏 luogu 发现没有连边,只有删边? 考虑倒着做 开map记M[i][j]表示编号为i的并查集,信仰j的人数 s[i]表示编号为i的并查集的总人数 首先询问 ...
- Jquery的parent和parents(找到某一特定的祖先元素)用法(转发:https://blog.csdn.net/cui_angel/article/details/7903704)
<!-- parent是指取得一个包含着所有匹配元素的唯一父元素的元素集合. parents则是取得一个包含着所有匹配元素的祖先元素的元素集合(不包含根元素).可以通过一个可选的表达式进行筛选. ...
- 制作透明的图标ICO
1.使用crowldraw画图保存为PNG格式,选择"被遮盖区域",然后保存(保存为PNG的透明格式). 2.使用IconWorkshop把透明的PNG格式导出为ICO.
- java中接口的概念及使用(补充final修饰符的使用)
接口 初期理解,可以是一个特殊的抽象类 当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示 class 用于定义类 interface 用于定义接口 接口定义时,格式特点: 1.接口中常见的 ...
- dsp2812 pwm配置
肚子疼了好几天,今天稍微好点,简单写点东西. 好几个月前做的项目,有些地方已经记不清楚了,但是突然客户又来问关于代码配置的情况,重新查看了代码,把相关的知识也整理一下. dsp2812中有好几个时钟相 ...
- day4 内置函数 迭代器&生成器 yield总结 三元运算 闭包
内置函数: 内置函数 # abs()返回一个数字的绝对值.如果给出复数,返回值就是该复数的模. b = -100 print(b) print(abs(b)) # all() 所有为真才为真,只要有一 ...
- Html 练习
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...