(模板)Luogu3380-2B平衡树

Problem

传送门

一个长度为n的序列,支持一堆操作,大致操作如下:

1.k在区间的排名(由小到大)2.区间第k小;3.单点修改;4&5:k的在区间上的前驱/后继。

Solution

右边大佬说树套树很简单,就是两个基本操作套起来即可。

然后我码了一个半小时才码完。

timg

虽然话没说错,树状数组套主席树……

但是这代码……

算了,还是太菜了……

2,3操作:

其实做法比较好理解,树状数组具有前缀性,主席树也是利用前缀

所以可以将树状数组的每一个节点上建一颗主席树

这样就可以完美的实现修改操作了

具体实现……就是把原本的树状数组一般操作改为主席树上的修改操作

询问的时候将树状数组上\(lowbit\)到的点全部带进去主席树里去询问就可以了。

以上是第2,3操作(搞了半天才完成2,3操作)

1操作:

考虑线段树的遍历过程

如果当前权值线段树的\(mid\)大于当前询问的权值k,那么我们会走向左儿子,否则往走向右儿子

而且,当我们走向右儿子时k一定大于左边的所有数

所以我们只要在此时加左子树的数的个数即可

4,5操作:

既然知道了任意数在区间里的\(rank\)前驱和后继就很好处理了

\(k\)前驱只需要查\(k\)在区间里的\(rank\),区间排名为\(rank - 1\)的数即为所求

\(k\)的后继则需要知道\(k\)在区间中的\(rank\)\(k\)在区间中出现的次数\(num\),再求区间中排名为\(rank+num\)的数即可。

放一份奇丑的代码,以后再改。

Code

#include <bits/stdc++.h>

using namespace std;

#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
#define fst first
#define snd second

template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }

inline int read(){
	int res = 0, fl = 1;
	char r = getchar();
	for (; !isdigit(r); r = getchar()) if(r == '-') fl = -1;
	for (; isdigit(r); r = getchar()) res = (res << 3) + (res << 1) + r - 48;
	return res * fl;
}
typedef long long LL;
typedef pair<int, int> pii;
const int Maxn = 4e5 + 10;

struct CMtree{
	int ls, rs, sum;
}tre[Maxn << 7];
struct SGT{
	int ch[20],siz;
	SGT(){ siz = 0;}
	SGT Ls(){
		SGT B;
		for (int i = 1; i <= siz; ++i) B.ch[i] = tre[ch[i]].ls;
		B.siz = siz;
		return B;
	}
	SGT Rs(){
		SGT B;
		for (int i = 1; i <= siz; ++i) B.ch[i] = tre[ch[i]].rs;
		B.siz = siz;
		return B;
	}
	int sum(){
		int num = 0;
		for (int i = 1; i <= siz; ++i) num += tre[ch[i]].sum;
		return num;
	}
};
int A[Maxn], n, m, cnt, root[Maxn << 6];
int INF = 1e8 + 10;
pii operator + (const pii a, const pii b){
	return mp(a.fst + b.fst, a.snd + b.snd);
}
namespace CMT{
	inline void modify(int &rt,int l, int r, int pos, int v){
		if(!rt) rt = ++cnt;
		tre[rt].sum += v;
		if(l == r) return;
		int mid = l + r >> 1;
		if(mid >= pos) modify(tre[rt].ls, l, mid, pos, v);
		else modify(tre[rt].rs, mid + 1, r, pos, v);
	}
	inline void build(int &rt, int grt,int l, int r, int pos){
		tre[rt = ++cnt] = tre[grt];
		tre[rt].sum++;
		if(l == r) return;
		int mid = l + r >> 1;
		if(mid >= pos) build(tre[rt].ls, tre[grt].ls, l, mid, pos);
		else build(tre[rt].rs, tre[grt].rs, mid + 1, r, pos);
	}
	inline int Query(SGT a, SGT b, int l, int r, int k){
		if(l == r) return l;
		int mid = l + r >> 1, t = b.Ls().sum() - a.Ls().sum();
		//printf("%d %d %d %d\n", l, r, t, k);
		if(k <= t) return Query(a.Ls(), b.Ls(), l, mid, k);
		else return Query(a.Rs(), b.Rs(), mid + 1, r, k - t);
	}
	inline pii rank(SGT a, SGT b,int l,int r, int k){
		if(l == r) {
			return mp(1,b.sum() - a.sum());
		}
		int mid = l + r >> 1;
		if(k <= mid) return rank(a.Ls(), b.Ls(), l, mid, k);
		else return mp(b.Ls().sum() - a.Ls().sum(), 0) + rank(a.Rs(), b.Rs(), mid + 1, r, k);
	}
}
namespace BIT{
	int lst[Maxn];
	inline int lowbit(int x) {return x & -x;}
	inline void change(int pos,int a, int b){
		for (; pos <= n; pos += lowbit(pos))
			CMT :: modify(root[pos], 1,INF, a, -1), CMT :: modify(root[pos], 1,INF, b, 1);
	}
	inline void add(int pos,int a){
		for (; pos <= n; pos += lowbit(pos)){
			CMT :: build(root[pos], lst[pos], 1, INF, a), lst[pos] = root[pos];
		}
	}
	inline pii Query(int l, int r, int k, bool fl){
		SGT a, b;
		for (int i = l - 1; i > 0; i -= lowbit(i)) a.ch[++a.siz] = root[i];
		for (int i = r; i > 0; i -= lowbit(i)) b.ch[++b.siz] = root[i];
		if(fl) return mp(CMT :: Query(a, b, 1, INF, k), 0);
		else return CMT :: rank(a, b, 1, INF, k);
	}
}
void Front(int l, int r, int k) {
	pii Rank = BIT::Query(l, r, k, 0);
	if(Rank.fst == 1) printf("-2147483647\n");
	else printf("%d\n",BIT::Query(l, r, Rank.fst - 1, 1).fst);
}
void Next(int l, int r, int k){
	pii Rank = BIT::Query(l, r, k, 0);
	int all = r - l + 1;
	if(Rank.fst + Rank.snd > all) printf("2147483647\n");
	else printf("%d\n",BIT::Query(l, r, Rank.fst + Rank.snd, 1).fst);
}
int main()
{
	n = read(), m = read();
	for (int i = 1; i <= n; ++i) A[i] = read(), BIT::add(i, A[i]);
	while(m--){
		int opt = read();
		if(opt == 3) {int pos = read(), k = read(); BIT::change(pos,A[pos],k); A[pos] = k; continue;}
		int l = read(), r = read(), k = read();
		if(opt == 1) printf("%d\n",BIT::Query(l, r, k, 0).fst);
		if(opt == 2) printf("%d\n",BIT::Query(l, r, k, 1).fst);
		if(opt == 4) Front(l, r, k);
		if(opt == 5) Next(l, r, k);
	}
	return 0;
}


posted @ 2019-02-18 20:45  LZY_caiji  阅读(188)  评论(0编辑  收藏  举报
Live2D //博客园自带,可加可不加