zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    HDU 2196 Computer
    HDU 1520 Anniversary party
    POJ 1217 FOUR QUARTERS
    POJ 2184 Cow Exhibition
    HDU 2639 Bone Collector II
    POJ 3181 Dollar Dayz
    POJ 1787 Charlie's Change
    POJ 2063 Investment
    HDU 1114 Piggy-Bank
    Lca hdu 2874 Connections between cities
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12757860.html
Copyright © 2011-2022 走看看