zoukankan      html  css  js  c++  java
  • BZOJ3600 没有人的算术(替罪羊树,线段树)

    BZOJ3600 没有人的算术(替罪羊树,线段树)

    解题思路

    好神奇的数据结构题!l !1

    题目大概意思是说你可以快速判断两个元素的大小,并且满足偏序关系。

    单点修改,求区间最大值。

    题目用二元组满足偏序关系确实巧妙。

    因为满足偏序关系,所以我们可以给它们对应一个具体的数字,这样比较时直接比较这个数字就行了。

    但是我们需要支持动态标号,如果采用一个排列来标号的话插入一个数会有一大堆数字的变化发生变化。

    我们考虑用实数来实现,整个值域从 [1,1e9] 开始,维护一个 bst,插入时自己的值就取可选值域的一半。

    但事实上如果 bst 深度很大的话也会被卡满的!!1

    我们需要一个保证深度较小的平衡树,而且不要有复杂的操作,发现替罪羊树支持我们所有的操作,暴力重构在这题中变得十分优美。

    另外序列上的问题我们需要维护一棵线段树,线段树要注意的是暴力重构时不必重新修改线段树上涉及的所有节点,注意到偏序关系不会变,如果线段树上记录较大值是哪个节点而不是具体值即可。

    代码:

    const int N = 100059;
    const int M = 500909;
    int V[M], cnt;
    struct node {
    	int ls, rs;
    	node (int l = 0, int r = 0) : ls(l), rs(r) {}
    	bool operator < (const node &i) const {
    		return ls != i.ls ? V[ls] < V[i.ls] : V[rs] < V[i.rs];
    	}
    	bool operator == (const node &i) const { return ls == i.ls && rs == i.rs; }
    }val[M];
    
    #define ls p << 1
    #define rs ls | 1
    int id[N], mx[N<<2], rt, m, n;
    void build(int p, int l, int r) {
    	mx[p] = l; if (l == r) return ;
    	int mid = (l + r) >> 1;
    	build(ls, l, mid), build(rs, mid + 1, r);
    }
    
    inline bool cmp(int x, int y) { return V[id[x]] >= V[id[y]]; }
    void change(int p, int l, int r, int x) {
    	if (l == r) return mx[p] = l, void();
    	int mid = (l + r) >> 1;
    	x <= mid ? change(ls, l, mid, x) : change(rs, mid + 1, r, x);
    	mx[p] = cmp(mx[ls], mx[rs]) ? mx[ls] : mx[rs];
    }
    
    int query(int p, int l, int r, int L, int R) {
    	if (L <= l && r <= R) return mx[p];
    	int mid = (l + r) >> 1, res = 0;
    	if (L <= mid) res = query(ls, l, mid, L, R);
    	if (R > mid) {
    		int t = query(rs, mid + 1, r, L, R);
    		if (!cmp(res, t)) res = t;
    	}
    	return res;
    }
    
    namespace SCT {
    	#undef ls
    	#undef rs
    	int st[M], siz[M], ls[M], rs[M], tp;
    	void pia(int x) { if (ls[x]) pia(ls[x]); st[++tp] = x; if (rs[x]) pia(rs[x]); }
    	int build(int l, int r, int L, int R) {
    		int mid = (l + r) >> 1, x = st[mid];
    		int m2 = V[x] = (L + R) >> 1;
    		ls[x] = l < mid ? build(l, mid - 1, L, m2 - 1) : 0;
    		rs[x] = r > mid ? build(mid + 1, r, m2 + 1, R) : 0;
    		if (l == r) return siz[st[l]] = 1, st[l];
    		return siz[x] = siz[ls[x]] + siz[rs[x]], x;
    	}
    	void rebuild(int &p, int L, int R) { tp = 0, pia(p), p = build(1, tp, L, R); }
    	int insert(int &p, int l, int r, node t) {
    		if (!p) { val[p = ++cnt] = t, V[p] = (l + r) >> 1; siz[p] = 1; return p; }
    		int mid = (l + r) >> 1, res = 0;
    		if (t == val[p]) return p;
    		if (t < val[p]) res = insert(ls[p], l, mid - 1, t);
    		else res = insert(rs[p], mid + 1, r, t);
    		siz[p] = siz[ls[p]] + siz[rs[p]] + 1;
    		if (max(siz[ls[p]], siz[rs[p]]) >= siz[p] * 0.73) rebuild(p, l, r);
    		return res;
    	}
    }
    
    char op[5];
    int main() {
    	read(n), read(m); V[0] = val[0].ls = -1, SCT::insert(rt, 1, 1e9, node(0, 0));
    	for (int i = 1;i <= n; ++i) id[i] = 1; build(1, 1, n);
    	for (int i = 1, l, r, k;i <= m; ++i) {
    		scanf ("%s", op), read(l), read(r);
    		if (op[0] == 'C') {
    			read(k), id[k] = SCT::insert(rt, 1, 1e9, node(id[l], id[r]));
    			change(1, 1, n, k);
    		} else write(query(1, 1, n, l, r));
    	}
    	return 0;
    }
    
    /*
    
    5 10
    C 1 1 1
    C 2 1 2
    Q 1 2
    C 4 4 4
    C 5 5 5
    Q 4 5
    Q 3 3
    C 4 2 3
    C 4 4 4
    Q 3 4
    
    */
    
  • 相关阅读:
    Azure 虚拟机安全加固整理
    AzureARM 使用 powershell 扩容系统磁盘大小
    Azure Linux 云主机使用Root超级用户登录
    Open edX 配置 O365 SMTP
    powershell 根据错误GUID查寻错误详情
    azure 创建redhat镜像帮助
    Azure Powershell blob中指定的vhd创建虚拟机
    Azure Powershell 获取可用镜像 PublisherName,Offer,Skus,Version
    Power BI 连接到 Azure 账单,自动生成报表,可刷新
    Azure powershell 获取 vmSize 可用列表的命令
  • 原文地址:https://www.cnblogs.com/Hs-black/p/14346643.html
Copyright © 2011-2022 走看看