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

news/2024/11/15 4:45:14/

传送门
题意:
支持插入一个向量,删去某一个现有的向量,查询现有的所有向量与给出的一个向量的点积的最大值。


思路:
考虑线段树分治。
先对于每个向量处理出其有效时间放到线段树上面,然后考虑查询:对于两个已有的向量 ( u 1 , v 1 ) (u_1,v_1) (u1,v1) ( u 2 , v 2 ) (u_2,v_2) (u2,v2),假设给出的向量为 ( x 0 , y 0 ) (x_0,y_0) (x0,y0) u 1 > u 2 & & ( u 1 , v 1 ) ⋅ ( x 0 , y 0 ) > ( u 2 , v 2 ) ⋅ ( x 0 , y 0 ) u_1>u_2\&\&(u_1,v_1)\cdot(x_0,y_0)>(u_2,v_2)\cdot(x_0,y_0) u1>u2&&(u1,v1)(x0,y0)>(u2,v2)(x0,y0)
那么展开得知: ( u 1 − u 2 ) x 0 > − ( v 1 − v 2 ) y 0 ⇒ − x 0 y 0 > v 1 − v 2 u 1 − u 2 (u_1-u_2)x_0>-(v_1-v_2)y_0\Rightarrow-\frac{x_0}{y_0}>\frac{v_1-v_2}{u_1-u_2} (u1u2)x0>(v1v2)y0y0x0>u1u2v1v2
说明在凸包上,于是对于每个线段树节点维护一个凸包,查询的时候在上面二分即可。
代码:

#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
inline int read(){int ans=0;char ch=getchar();while(!isdigit(ch))ch=getchar();while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();return ans;
}
typedef long long ll;
const int N=200005;
int n,tot1=0,tot2=0,q[N],top;
struct Node{int l,r;ll x,y;}a[N];
ll ans[N];
struct pot{ll x,y;pot(ll _x=0,ll _y=0):x(_x),y(_y){}friend inline pot operator+(const pot&a,const pot&b){return pot(a.x+b.x,a.y+b.y);}friend inline pot operator-(const pot&a,const pot&b){return pot(a.x-b.x,a.y-b.y);}friend inline ll operator^(const pot&a,const pot&b){return a.x*b.y-a.y*b.x;}friend inline ll operator*(const pot&a,const pot&b){return a.x*b.x+a.y*b.y;}friend inline bool operator<(const pot&a,const pot&b){return a.x==b.x?a.y<b.y:a.x<b.x;}
}b[N];
typedef pair<int,pot> pii;
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
vector<pot>upd[N<<2];
inline void update(int p,int l,int r,int ql,int qr,pot v){if(ql>r||qr<l)return;if(ql<=l&&r<=qr)return upd[p].push_back(v);if(qr<=mid)update(lc,l,mid,ql,qr,v);else if(ql>mid)update(rc,mid+1,r,ql,qr,v);else update(lc,l,mid,ql,qr,v),update(rc,mid+1,r,ql,qr,v);
}
inline ll max(const ll&a,const ll&b){return a>b?a:b;}
inline ll max(const ll&a,const ll&b,const ll&c){return a>b?(a>c?a:c):(b>c?b:c);}
inline double slope(pot a,pot b){return a.x==b.x?1e9:(double)(a.y-b.y)/(double)(a.x-b.x);}
inline ll query(int p,pot tmp){ll ret=0;if(top<=3){for(ri i=1;i<=top;++i)ret=max(ret,tmp*upd[p][q[i]]);return ret;}double slop=-(double)tmp.x/(double)tmp.y;if(slop>slope(upd[p][q[2]],upd[p][q[1]]))return tmp*upd[p][q[1]];if(slop<slope(upd[p][q[top]],upd[p][q[top-1]]))return tmp*upd[p][q[top]];ret=max(tmp*upd[p][q[1]],tmp*upd[p][q[top]]);int l=2,r=top,res=1;while(l<=r){int Mid=l+r>>1;if(slop<slope(upd[p][q[Mid]],upd[p][q[Mid-1]]))l=Mid+1,res=Mid;else r=Mid-1;}return tmp*upd[p][q[res]];
}
inline void calc(int p,int l,int r){if(!upd[p].size())return;sort(upd[p].begin(),upd[p].end());q[top=1]=0;for(ri i=1,up=upd[p].size()-1;i<=up;++i){while(top>1&&((upd[p][i]-upd[p][q[top-1]])^(upd[p][q[top]]-upd[p][q[top-1]]))<=0)--top;q[++top]=i;}for(ri i=l;i<=r;++i)ans[i]=max(ans[i],query(p,b[i]));
}
inline void solve(int p,int l,int r){calc(p,l,r);if(l==r)return;solve(lc,l,mid),solve(rc,mid+1,r);
}
#undef lc
#undef rc
#undef mid
int main(){n=read();for(ri op,x,y,i=1;i<=n;++i){op=read();if(op==1)x=read(),y=read(),a[++tot1]=(Node){tot2+1,-1,x,y};if(op==2)a[read()].r=tot2;if(op==3)b[++tot2].x=read(),b[tot2].y=read();}for(ri i=1;i<=tot1;++i)update(1,1,tot2,a[i].l,~a[i].r?a[i].r:tot2,pot(a[i].x,a[i].y));solve(1,1,tot2);for(ri i=1;i<=tot2;++i)cout<<ans[i]<<'\n';return 0;
}

http://www.ppmy.cn/news/554514.html

相关文章

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

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

洛谷P4311 士兵占领

题目链接&#xff1a;https://www.luogu.org/problemnew/show/P4311 知识点&#xff1a;  最大流 解题思路&#xff1a; 对于每一行&#xff0c;建立一条从源点到该行的边&#xff0c;容量为这一行能不放置士兵的点数&#xff1b; 对于每一列&#xff0c;建立一条从该列到汇点…

hdu_4311_Meeting point-1(曼哈顿距离)及其拓展

hdu_4311_Meeting point-1(曼哈顿距离&#xff09;及其拓展 题目链接 题目描述 给定n个点&#xff0c;找出其中一个点&#xff0c;使得其他点到这个点的曼哈顿距离和最小&#xff0c;求这个最小距离和。 Sample Input 4 6 -4 -1 -1 -2 2 -4 0 2 0 3 5 -2 6 0 0 2 0 -5 -2 2 …

jzoj4311 统一天下

Description Input Output Sample Input 4 4 1 3 2 1 4 3 4 3 4 1 1 2 Sample Output 68 Data Constraint 算法讨论 问题的关键是如何求出两棵树的重心&#xff0c;那就是f[i]&#xff0c;即所有点到点i的距离&#xff0c;首先dfs一次求出f[1]和z[i](i的子树的大小)…

HDU 4311 Meeting point-1

2016暑期集训1-A HDU 4311 Meeting point-1 预处理&#xff0c;前缀和&#xff0c;递推计算&#xff0c;距离去绝对值技巧 传送门&#xff1a;HustOJ 传送门&#xff1a;HDU 题意 平面上有n个点&#xff0c;定义两点间的距离D为 |x1-x2| |y1-y2|。从n个点中找到一点&#x…

P4311 士兵占领 上下界费用流 or 最大流

题目描述 有一个M * N的棋盘&#xff0c;有的格子是障碍。现在你要选择一些格子来放置一些士兵&#xff0c;一个格子里最多可以放置一个士兵&#xff0c;障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的…

【线段树分治】[BZOJ4311]向量

题目描述 Description 你要维护一个向量集合&#xff0c;支持以下操作&#xff1a; 1.插入一个向量(x,y) 2.删除插入的第i个向量 3.查询当前集合与(x,y)点积的最大值是多少。如果当前是空集输出0 Input 第一行输入一个整数n&#xff0c;表示操作个数 接下来n行&#xff0c;每行…

bzoj4311向量(线段树分治+斜率优化)

第二道线段树分治。 首先设当前向量是(x,y)&#xff0c;剩余有两个不同的向量(u1,v1)(u2,v2)&#xff0c;假设u1>u2&#xff0c;则移项可得&#xff0c;若(u1,v1)优于(u2,v2)&#xff0c;则-x/y>(v1-v2)/(u1-u2)&#xff0c;然后维护上凸壳后进行三分即可&#xff0c;复杂…