BZOJ3533 [Sdoi2014]向量集 【线段树 + 凸包 + 三分】
2018-05-20 19:29
295 查看
题目链接
题解
我们设询问的向量为\((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要足够大
②整型三分的姿势
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<vector> #include<map> #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define mp(a,b) make_pair<int,int>(a,b) #define cls(s) memset(s,0,sizeof(s)) #define cp pair<int,int> #define LL long long int #define pb push_back #define ls (u << 1) #define rs (u << 1 | 1) using namespace std; const int maxn = 400005,maxm = 100005; const LL INF = 9223372036854775807ll; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } struct point{ LL x,y; }p[maxn],t[maxn]; inline point operator -(const point& a,const point& b){ return (point){a.x - b.x,a.y - b.y}; } inline point operator +(const point& a,const point& b){ return (point){a.x + b.x,a.y + b.y}; } inline LL cross(const point& a,const point& b){ return a.x * b.y - a.y * b.x; } inline LL operator *(const point& a,const point& b){ return a.x * b.x + a.y * b.y; } inline double slope(const point& a,const point& b){ if (a.x == b.x) return INF; return 1.0 * (a.y - b.y) / (a.x - b.x); } inline bool operator <(const point& a,const point& b){ return a.x == b.x ? a.y < b.y : a.x < b.x; } inline bool operator ==(const point& a,const point& b){ return a.x == b.x && a.y == b.y; } int n,now; char S; LL lans; inline int decode (int x ,LL lastans) { return S == 'E' ? x : (x ^ (lastans & 0x7fffffff)); } vector<point> Tu[maxn << 2],Td[maxn << 2]; int top[maxn << 2],Top[maxn << 2]; point st[maxn]; void build(int u,int l,int r){ int N = 0; for (int i = l; i <= r; i++) t[++N] = p[i]; sort(t + 1,t + 1 + N); top[u] = -1; for (int i = 1; i <= N; i++){ if (i > 1 && t[i] == t[i - 1]) continue; while (top[u] > 0 && cross(st[top[u]] - st[top[u] - 1],t[i] - st[top[u]]) >= 0) top[u]--; st[++top[u]] = t[i]; } for (int i = 0; i <= top[u]; i++) Tu[u].pb(st[i]); Top[u] = -1; for (int i = 1; i <= N; i++){ if (i > 1 && t[i] == t[i - 1]) continue; while (Top[u] > 0 && cross(st[Top[u]] - st[Top[u] - 1],t[i] - st[Top[u]]) <= 0) Top[u]--; st[++Top[u]] = t[i]; } for (int i = 0; i <= Top[u]; i++) Td[u].pb(st[i]); } void insert(int u,int l,int r){ if (l == r){Tu[u].pb(p[now]); Td[u].pb(p[now]); top[u] = Top[u] = 0; return;} if (now == r) build(u,l,r); int mid = l + r >> 1; if (mid >= now) insert(ls,l,mid); else insert(rs,mid + 1,r); } LL qmax(int u,point P){ if (P.y >= 0){ int l = 0,r = top[u],lmid,rmid; while (r - l >= 3){ lmid = (l + l + r) / 3; rmid = (r + l + r) / 3; if (P * Tu[u][lmid] <= P * Tu[u][rmid]) l = lmid; else r = rmid; } LL ans = -INF; for (int i = l; i <= r; i++) ans = max(ans,P * Tu[u][i]); return ans; } else { int l = 0,r = Top[u],lmid,rmid; while (r - l >= 3){ lmid = (l + l + r) / 3; rmid = (r + l + r) / 3; if (P * Td[u][lmid] <= P * Td[u][rmid]) l = lmid; else r = rmid; } LL ans = -INF; for (int i = l; i <= r; i++) ans = max(ans,P * Td[u][i]); return ans; } } LL query(int u,int l,int r,int L,int R,point a){ if (l >= L && r <= R) return qmax(u,a); int mid = l + r >> 1; if (mid >= R) return query(ls,l,mid,L,R,a); if (mid < L) return query(rs,mid + 1,r,L,R,a); return max(query(ls,l,mid,L,R,a),query(rs,mid + 1,r,L,R,a)); } int main(){ n = read(); scanf("%c",&S); char opt; int x,y,l,r; for (int i = 1; i <= n; i++){ opt = getchar(); while (opt != 'A' && opt != 'Q') opt = getchar(); x = decode(read(),lans); y = decode(read(),lans); if (opt == 'A'){ p[++now] = (point){x,y}; insert(1,1,n); } else { l = decode(read(),lans); r = decode(read(),lans); lans = query(1,1,n,l,r,(point){x,y}); printf("%lld\n",lans); } } return 0; }
相关文章推荐
- BZOJ 3533: [Sdoi2014]向量集( 线段树 + 三分 )
- BZOJ 3533 [Sdoi2014]向量集(线段树套凸包)(含对拍)
- bzoj 3533 [Sdoi2014]向量集 凸包
- 【bzoj3533】[Sdoi2014]向量集 三分+线段树+凸包
- 【BZOJ】【P3533】【Sdoi2014】【向量集】【题解】【线段树+凸包+三分】
- BZOJ3533 SDOI2014 向量集
- BZOJ3533: [Sdoi2014]向量集
- bzoj 3533 [Sdoi2014]向量集 线段树+凸包+三分(+动态开数组) 好题
- bzoj3533【SDOI2014】向量集
- BZOJ 3533 sdoi 2014 向量集
- 【bzoj3533】[Sdoi2014]向量集 线段树+STL-vector维护凸包
- BZOJ 3533 Sdoi2014 向量集 线段树+凸包+三分
- Bzoj3533:[Sdoi2014]向量集:线段树+凸包+三分
- 【bzoj4311】向量 线段树按时间分治+凸包+三分
- bzoj 3533: [Sdoi2014]向量集 线段树维护凸包
- [BZOJ4311]向量(凸包+三分+线段树分治)
- BZOJ 4311: 向量(线段树分治+凸包+三分)
- BZOJ 3533 Sdoi2014 向量集
- BZOJ3533: [Sdoi2014]向量集
- [Sdoi 2014] bzoj3533 向量集 [线段树+凸包+三分]