zoukankan      html  css  js  c++  java
  • UOJ#191. 【集训队互测2016】Unknown

    传送门
    这个题目实际上可以建立出树,然后重链剖分维护一条链的凸包
    然后离线询问排序斜率做到 (nlog^2n),或者点分治+平衡树也行
    但是这个题目卡空间,数组一不小心就爆了卡一卡也能过
    考虑其它空间常数小并且又好写的做法
    根据一般的二进制分组的方法,每次这个块满了就合并儿子的凸包
    这样显然不对,只要又删又加就假了
    我们换一种方法,每次这个块满了就合并线段树同一层前一个节点的儿子的凸包
    这样每次都要花费 (len) 次添加操作才能换来一次 (2len) 的合并
    此时的没有合并节点顶多 (2log)
    查询就定位每个节点,在凸包上二分即可
    时间 (nlog^2n) 空间 (nlogn)

    # include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    namespace IO {
    	const int maxn(1 << 21 | 1);
    
    	char ibuf[maxn], *iS, *iT, c;
    	int f;
    	
    	inline char Getc() {
    		return iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, maxn, stdin), (iS == iT ? EOF : *iS++)) : *iS++;
    	}
    
    	template <class Int> inline void In(Int &x) {
    		for (c = Getc(), f = 1; c < '0' || c > '9'; c = Getc()) f = c == '-' ? -1 : 1;
    		for (x = 0; c >= '0' && c <= '9'; c = Getc()) x = (x << 1) + (x << 3) + (c ^ 48);
    		x *= f;
    	}
    }
    
    using IO :: In;
    
    const int maxn(1 << 20 | 1);
    const int mod(998244353);
    const ll inf(1e18);
    
    struct Point {
    	int x, y;
    
    	inline Point(int _x = 0, int _y = 0) {
    		x = _x, y = _y;
    	}
    	
    	inline Point operator -(Point b) const {
    		return Point(x - b.x, y - b.y);
    	}
    
    	inline ll operator *(Point b) const {
    		return (ll)x * b.y - (ll)y * b.x;
    	}
    } cur;
    
    int tp, m, mx, n, mxr;
    bitset <maxn> done;
    vector <Point> vc[maxn];
    
    inline void Merge(int ls, int rs, int ff) {
    	done[ff] = 1;
    	int i, j, l1, l2, l3;
    	vc[ff].clear(), l1 = vc[ls].size(), l2 = vc[rs].size();
    	for (i = j = l3 = 0; i < l1 || j < l2; ) {
    		if (j == l2 || (i < l1 && (vc[ls][i].x < vc[rs][j].x || (vc[ls][i].x == vc[rs][j].x && vc[ls][i].y < vc[rs][j].y)))) {
    			while (l3 > 1 && (vc[ff][l3 - 1] - vc[ff][l3 - 2]) * (vc[ls][i] - vc[ff][l3 - 2]) >= 0) vc[ff].pop_back(), --l3;
    			vc[ff].push_back(vc[ls][i]), ++i, ++l3;
    		}
    		else {
    			while (l3 > 1 && (vc[ff][l3 - 1] - vc[ff][l3 - 2]) * (vc[rs][j] - vc[ff][l3 - 2]) >= 0) vc[ff].pop_back(), --l3;
    			vc[ff].push_back(vc[rs][j]), ++j, ++l3;
    		}
    	}
    }
    
    inline ll Calc(int x) {
    	if (!vc[x].size()) return -inf;
    	int l, r, mid, ans;
    	ans = vc[x].size() - 1, l = 0, r = vc[x].size() - 2;
    	while (l <= r) {
    		mid = (l + r) >> 1;
    		if ((vc[x][mid + 1] - vc[x][mid]) * cur >= 0) ans = mid, r = mid - 1;
    		else l = mid + 1;
    	}
    	return Point(cur.x, cur.y) * vc[x][ans];
    }
    
    void Insert(int x, int l, int r, int p) {
    	int mid;
    	if (l == r) {
    		mxr = max(mxr, x);
    		vc[x].push_back(cur), done[x] = 1;
    		return;
    	}
    	mid = (l + r) >> 1;
    	p <= mid ? Insert(x << 1, l, mid, p) : Insert(x << 1 | 1, mid + 1, r, p);
    	if (x == (x & -x)) return;
    	if (p == r && !done[x - 1]) Merge((x - 1) << 1, (x - 1) << 1 | 1, x - 1);
    }
    
    void Delete(int x, int l, int r, int p) {
    	int mid;
    	done[x] = 0;
    	if (l == r) {
    		mxr = max(mxr, x);
    		vc[x].pop_back();
    		return;
    	}
    	mid = (l + r) >> 1;
    	p <= mid ? Delete(x << 1, l, mid, p) : Delete(x << 1 | 1, mid + 1, r, p);
    }
    
    ll Query(int x, int l, int r, int ql, int qr) {
    	int mid;
    	ll ret;
    	if (ql <= l && qr >= r && done[x]) return Calc(x);
    	if (l == r) return -inf;
    	ret = -inf, mid = (l + r) >> 1;
    	if (ql <= mid) ret = Query(x << 1, l, mid, ql, qr);
    	if (qr > mid) ret = max(ret, Query(x << 1 | 1, mid + 1, r, ql, qr));
    	return ret;
    }
    
    int main() {
    	int i, op, x, y, l, r, ans;
    	In(tp);
    	while (In(m), m) {
    		ans = n = 0, done.reset();
    		for (i = 1; i <= mxr; ++i) vc[i].clear();
    		for (mxr = 0, mx = 1; mx <= 300000; mx <<= 1);
    		for (i = 1; i <= m; ++i) {
    			In(op);
    			if (op == 1) In(x), In(y), cur = Point(x, y), Insert(1, 1, mx, ++n);
    			else if (op == 2) Delete(1, 1, mx, n), --n;
    			else {
    				In(l), In(r), In(x), In(y), cur = Point(x, y);
    				ans ^= (Query(1, 1, mx, l, r) % mod + mod) % mod;
    			}
    		}
    		printf("%d
    ", ans);
    	}
        return 0;
    }
    
  • 相关阅读:
    后缀数组/LCP
    Manachar's Algorithm
    自动AC机qwq(大雾)以及trie图fail图的一些结论
    平衡树有关题目小结
    洛谷日报索引(转)
    初始化函数的简单写法
    关于对拍
    第12组 Alpha冲刺(4/6)
    第12组 Alpha冲刺(3/6)
    第12组 Alpha冲刺(2/6)
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/10254552.html
Copyright © 2011-2022 走看看