主席树动态

主席树动态

以ZOJ2114为模板题。

附上此题链接

主席树的动态单点改值主要是主席树加树状数组,具体暂未理解,待熟练仔细揣摩。

代码如下

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 60000;
struct NOOD {
	bool kind;
	int l, r, k, v;
}Q[maxn + 5];
int a[maxn + 5], t[2 * maxn + 5];
int root[maxn * 32 + 5], L[maxn * 32 + 5], R[maxn * 32 + 5], cnt[maxn * 32 + 5];
int S[maxn + 5], ul[maxn + 5], ur[maxn + 5];
int n, m, q, tot;
void Build(int &rt, int l, int r) {
	rt = ++tot;
	cnt[rt] = 0;
	if(l == r) return ;
	int mid = (l + r) / 2;
	Build(L[rt], l, mid);
	Build(R[rt], mid + 1, r);
}
void Insert(int &rt, int pre, int l, int r, int x, int val) {
	rt = ++tot;
	L[rt] = L[pre];
	R[rt] = R[pre];
	cnt[rt] = cnt[pre] + val;
	if(l == r)return ;
	int mid = (l + r) / 2;
	if(x <= mid)Insert(L[rt], L[pre], l, mid, x, val);
	else Insert(R[rt], R[pre], mid + 1, r, x, val);
}
int lowbit(int x){return x & -x;}
void add(int x, int val) {
	int pos = lower_bound(t + 1, t + m + 1, a[x]) - t;
	while(x <= n) {
		Insert(S[x], S[x], 1, m, pos, val);
		x += lowbit(x);
	}
}
int Sum(int x, bool kind) {
	int res = 0;
	while(x > 0) {
		if(kind == 0)res += cnt[L[ur[x]]];
		else res += cnt[L[ul[x]]];
		x -= lowbit(x);
	}
	return res;
}
int Query(int posl, int posr, int nodel, int noder, int l, int r, int k) {
	if(l == r)return l;
	int mid = (l + r) / 2;
	int num = Sum(posr, 0) - Sum(posl, 1) + cnt[L[noder]] - cnt[L[nodel]];//暂未明白此处树状数组求法
	if(k <= num) {
		for(int i = posr; i ; i -= lowbit(i))ur[i] = L[ur[i]];
		for(int i = posl; i ; i -= lowbit(i))ul[i] = L[ul[i]];
		return Query(posl, posr, L[nodel], L[noder], l, mid, k);
	}
	else {
		for(int i = posr; i ; i -= lowbit(i))ur[i] = R[ur[i]];
		for(int i = posl; i ; i -= lowbit(i))ul[i] = R[ul[i]];
		return Query(posl, posr, R[nodel], R[noder], mid + 1, r, k - num);
	}
}

void Init() {
	tot = 0;
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; t[i] = a[i], i++)scanf("%d", &a[i]);
	m = n;
	for(int i = 1; i <= q; i++) {
		char ch; scanf(" %c", &ch);
		if(ch == 'Q') {
			Q[i].kind = 0; 
			scanf("%d%d%d", &Q[i].l, &Q[i].r, &Q[i].k);
		}
		else {
			Q[i].kind = 1; 
			scanf("%d%d", &Q[i].l, &Q[i].v);
			t[++m] = Q[i].v;
		}
	}
	sort(t + 1, t + m + 1);
	m = unique(t + 1, t + m + 1) - t - 1;
}
int main() {
	int T; scanf("%d", &T);
	while(T--) {
		Init();
		Build(root[0], 1, m);
		for(int i = 1; i <= n; i++) {
			int pos = lower_bound(t + 1, t + m + 1, a[i]) - t;
			Insert(root[i], root[i - 1], 1, m, pos, 1);
			S[i] = root[0];
		}
		for(int i = 1; i <= q; i++) {
			if(Q[i].kind == 0) {
				for(int j = Q[i].r; j ; j -= lowbit(j))ur[j] = S[j];
				for(int j = Q[i].l - 1; j ; j -= lowbit(j))ul[j] = S[j];
				printf("%d\n", t[Query(Q[i].l - 1, Q[i].r, root[Q[i].l - 1], root[Q[i].r], 1, m, Q[i].k)]);
			}
			else {
				add(Q[i].l, -1);
				a[Q[i].l] = Q[i].v;
				add(Q[i].l, 1);
			}
		}
	}
	return 0;
}
posted @ 2018-10-15 17:56 呵呵!!! 阅读( ...) 评论( ...) 编辑 收藏
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值