• BZOJ4311 向量(线段树分治+凸包)


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

    题目大意

    你要维护一个向量集合,支持以下操作:

    1. 插入一个向量 (x, y)

    2. 删除插入的第 i 个向量

    3. 查询当前集合与 (x, y) 点积的最大值是多少。如果当前是空集输出 0

    数据范围

    $ n le 200000 , 1 le x,y le 10^6 $

    解题思路

    线段树分治好题

    首先发现对于一个向量所在的直线,垂直于它的所有直线斜率相等,这样的直线经过向量集合中的点且最靠右的即为答案,不难发现维护向量集合的凸包即可

    凸包不好合并更不好删除,考虑线段树分治,将每个向量出现的时间分为 $ log $ 段,挂在线段树上,并在线段树上每个点构建一个凸包,求解单个凸包时可以用三分,询问就是从根节点到叶节点所有答案的最小值

    我的写法中提前将点按 x 排序,常数回小一点把,凸包是一个节点构建完就询问的

    代码如下

    #pragma GCC optimize(3, "inline")
    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define Pa pair<ll, ll>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y); }
    
    const int N = 300500;
    int cnt, cnt2, T, tp;
    struct node {
    	ll x, y, l, r;
    	bool operator < (const node &i) const {
    		return x < i.x;
    	}
    }vec[N], v[N];
    
    vector<Pa > poi[N<<2];
    Pa st[N];
    
    #define ls p << 1
    #define rs ls | 1
    void change(int p, int l, int r, Pa x, int L, int R) {
    	if (L <= l && r <= R) return poi[p].push_back(x), void();
    	int mid = (l + r) >> 1;
    	if (L <= mid) change(ls, l, mid, x, L, R);
    	if (mid < R)  change(rs, mid + 1, r, x, L, R); 
    }
    
    double K(Pa a, Pa b, Pa c) {
    	return (a.se - b.se) * (a.fi - c.fi) < (a.se - c.se) * (a.fi - b.fi) ;
    }
    
    ll Ans(Pa a, Pa b) {
    	return a.fi * b.fi + a.se * b.se;
    }
    
    ll ans[N];
    void solve(int p, int l, int r) {
    	tp = 0;
    	for (auto x: poi[p]) {
    		while (tp > 1 && K(st[tp-1], st[tp], x)) tp--;
    		st[++tp] = x;
    	}
    	for (int i = l;i <= r; i++) {
    		if (!v[i].l) continue;
    		Pa t = MP(v[i].x, v[i].y);
    		int L = 1, R = tp, ti = 0;
    		while (L < R) {
    			ti++;
    			int m1 = (L + R) >> 1;
    			if (Ans(t, st[m1]) < Ans(t, st[m1+1])) L = m1 + 1;
    			else R = m1;
    		}
    		Mx(ans[v[i].l], Ans(t, st[R]));
    	}
    	if (l == r) return; int mid = (l + r) >> 1;
    	solve(ls, l, mid), solve(rs, mid + 1, r);
    }
    
    int main() {
    	freopen ("hs.in","r",stdin);
    	freopen ("hs.out","w",stdout); 
    	int n; read(n);
    	for (int i = 1;i <= n; i++) {
    		int op, x, y;
    		read(op), read(x);
    		if (op == 1)
    			read(y), vec[++cnt] = (node) { x, y, i, n };
    		else if (op == 2) vec[x].r = i;
    		else read(y), cnt2++, v[i] = (node) {x, y, cnt2, cnt2};
    	}
    	
    	sort(vec + 1, vec + cnt + 1);
    	for (int i = 1;i <= cnt; i++) 
    		change(1, 1, n, MP(vec[i].x, vec[i].y), vec[i].l, vec[i].r);
    	
    	solve(1, 1, n);
    	for (int i = 1;i <= cnt2; i++) printf ("%lld
    ", ans[i]);
    	
    	return 0;
    }
    
  • 相关阅读:
    C++随机迷宫生成[转载]
    浮点指令
    表盘
    TabControl+ListView
    ListView
    Tooltips2
    随机数
    Tooltips
    iOS9 http不能访问网络——在Xcode中将https改成http方式
    iOS开发——音频篇——音效的播放
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12757860.html
Copyright © 2020-2023  润新知