zoukankan      html  css  js  c++  java
  • BZOJ3533 [Sdoi2014]向量集 【线段树 + 凸包 + 三分】

    题目链接

    BZOJ3533

    题解

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

    [egin{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
    ",lans);
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Java对MongoDB的CRUD
    MongoDB数据库基本用法
    MySQL order by 排序结果不正确
    Linux shell 脚本 eq,ne,le,ge,lt,gt意义
    Linux shell 命令运行符 &,;,&& 区别
    Linux netstat 命令详解
    Linux ss 命令详解
    Linux sort 命令详解
    Linux sed 命令详解
    Linux xargs 命令详解
  • 原文地址:https://www.cnblogs.com/Mychael/p/9064278.html
Copyright © 2011-2022 走看看