zoukankan      html  css  js  c++  java
  • Luogu3380 二逼平衡树

    题目蓝链

    Description

    您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:

    1. 查询(k)在区间内的排名
    2. 查询区间内排名为(k)的值
    3. 修改某一位值上的数值
    4. 查询(k)在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
    5. 查询(k)在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

    Solution

    首先我们可以想到一个非常暴力的做法,就是在普通平衡树上套一个线段树。这种做法除了二操作的复杂度是(mathcal{O}(log^3 n)),其余均为(mathcal{O}(log^2 n))。正是因为这样,所以这种做法用pbds代替平衡树之后,再开个O2,跑得比下面那种做法还快 早晓得这个跑这么快就打这个了

    我们其实可以把内层改为权值线段树,然后外层再套一个树状数组/线段树(树状数组可以省一点点空间,线段树的常数是树状数组常数的一半) 我tm还不如直接写线段树。这样我们二操作就可以省去二分答案的那个(log),实现了所有操作复杂度均为(mathcal{O}(log^2 n))(如果你不想离散化,还会乘上一个常数)

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define fst first
    #define snd second
    #define mp make_pair
    #define squ(x) ((LL)(x) * (x))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    
    typedef long long LL;
    typedef pair<int, int> pii;
    
    template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
    
    inline int read() {
    	int sum = 0, fg = 1; char c = getchar();
    	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
    	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    	return fg * sum;
    }
    
    const int maxn = 5e4 + 10;
    const int inf = 1e8;
    
    pii operator + (const pii &a, const pii &b) { return mp(a.fst + b.fst, a.snd + b.snd); }
    
    struct node {
    	int ls, rs, v;
    }A[maxn * 444];
    
    struct sts {
    	int a[16], cnt;
    	sts(): cnt(0) { }
    	void ins(int x) { a[++cnt] = x; }
    	sts ls() {
    		sts res; res.cnt = cnt;
    		for (int i = 1; i <= cnt; i++) res.a[i] = A[a[i]].ls;
    		return res;
    	}
    	sts rs() {
    		sts res; res.cnt = cnt;
    		for (int i = 1; i <= cnt; i++) res.a[i] = A[a[i]].rs;
    		return res;
    	}
    	int sum() {
    		int res = 0;
    		for (int i = 1; i <= cnt; i++) res += A[a[i]].v;
    		return res;
    	}
    };
    
    int rt[maxn];
    namespace ST {
    	int cnt;
    	void change(int &rt, int l, int r, int x, int v) {
    		if (!rt) rt = ++cnt; A[rt].v += v;
    		if (l == r) return;
    		int mid = (l + r) >> 1;
    		if (x <= mid) change(A[rt].ls, l, mid, x, v);
    		else change(A[rt].rs, mid + 1, r, x, v);
    	}
    	pii query(sts a, sts b, int l, int r, int x) {
    		if (l == r) return mp(0, b.sum() - a.sum());
    		int mid = (l + r) >> 1;
    		int tot = (b.ls()).sum() - (a.ls()).sum();
    		if (x <= mid) return query(a.ls(), b.ls(), l, mid, x);
    		return mp(tot, 0) + query(a.rs(), b.rs(), mid + 1, r, x);
    	}
    	int rank(sts a, sts b, int l, int r, int k) {
    		if (l == r) return l;
    		int mid = (l + r) >> 1;
    		int tot = (b.ls()).sum() - (a.ls()).sum();
    		if (k <= tot) return rank(a.ls(), b.ls(), l, mid, k);
    		return rank(a.rs(), b.rs(), mid + 1, r, k - tot);
    	}
    }
    
    int n, m, a[maxn];
    
    namespace BIT {
    #define lowbit(x) ((x) & -(x))
    	void change(int x, int v, int op) {
    		for (int i = x; i <= n; i += lowbit(i))
    			ST::change(rt[i], 0, inf, v, op);
    	}
    	pii query(int l, int r, int k) {
    		sts L, R;
    		for (int i = r; i; i -= lowbit(i)) R.ins(rt[i]);
    		for (int i = l - 1; i; i -= lowbit(i)) L.ins(rt[i]);
    		return ST::query(L, R, 0, inf, k);
    	}
    	int rank(int l, int r, int k) {
    		sts L, R;
    		for (int i = r; i; i -= lowbit(i)) R.ins(rt[i]);
    		for (int i = l - 1; i; i -= lowbit(i)) L.ins(rt[i]);
    		return ST::rank(L, R, 0, inf, k);
    	}
    }
    
    int main() {
    #ifdef xunzhen
    	freopen("tree.in", "r", stdin);
    	freopen("tree.out", "w", stdout);
    #endif
    
    	n = read(), m = read();
    	for (int i = 1; i <= n; i++) BIT::change(i, a[i] = read(), 1);
    
    	for (int i = 1; i <= m; i++) {
    		int op = read();
    		if (op == 1) {
    			int l = read(), r = read(), k = read();
    			printf("%d
    ", BIT::query(l, r, k).fst + 1);
    		}
    		if (op == 2) {
    			int l = read(), r = read(), k = read();
    			printf("%d
    ", BIT::rank(l, r, k));
    		}
    		if (op == 3) {
    			int x = read();
    			BIT::change(x, a[x], -1), BIT::change(x, a[x] = read(), 1);
    		}
    		if (op == 4) {
    			int l = read(), r = read(), x = read();
    			pii res = BIT::query(l, r, x);
    			if (res.fst) printf("%d
    ", BIT::rank(l, r, res.fst));
    			else printf("-2147483647
    ");
    		}
    		if (op == 5) {
    			int l = read(), r = read(), x = read();
    			pii res = BIT::query(l, r, x);
    			if (res.fst + res.snd < (r - l + 1)) printf("%d
    ", BIT::rank(l, r, res.fst + res.snd + 1));
    			else printf("2147483647
    ");
    		}
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    Python 字符串格式化
    centos 7 & 6 优化脚本
    centos7.X 系统初始化>>优化
    重新嫁接rm命令
    ArcGIS Engine 10 开发常见问题的解决方法
    数据提交成功后如何避免alert被window.location.reload()影响
    服务器端IIS中部署带Office组件程序
    常用正则表达式
    C#解析XML
    使用Spire.Doc组件利用模板导出Word文档
  • 原文地址:https://www.cnblogs.com/xunzhen/p/10353789.html
Copyright © 2011-2022 走看看