ZOJ - 2112 Dynamic Rankings 动态主席树 主席树+树状数组

题目链接:https://vjudge.net/problem/ZOJ-2112

题意:能修改的查询第k大

学习博客:https://blog.csdn.net/WilliamSun0122/article/details/77885781

理解:修改pos位置x - >y的话,影响的是【pos,n】,所以用树状数组的思想维护,然后对于每个节点建立可持久化线段树,由x变为y的话就是x位置减一,y位置加一,复杂度:nlognlogn

 

#include <bits/stdc++.h>
using namespace std;
const int N = 50010;
#define lowbit(x) (x & (-x))

struct node1 {
	char op[2];
	int x, y, k;
}q[N];
struct node2 {
	int l, r;
	int val;
}tree[N * 40];
int n, m;
int a[N], c[N], b[N * 2], len;
int tot;
int root[N], rot[N];
int ul[N], ur[N];
int update1(int pre, int l, int r, int pos, int val) {
	int cur = ++tot;
	tree[cur] = tree[pre];
	tree[cur].val += val;
	if(l == r) return cur;
	int mid = (l + r) >> 1;
	if(pos <= mid) tree[cur].l = update1(tree[pre].l, l, mid, pos, val);
	else tree[cur].r = update1(tree[pre].r, mid + 1, r, pos, val);
	return cur;
}
void update2(int pos, int x, int val) {
	while(pos <= n) {
		rot[pos] = update1(rot[pos], 1, len, x, val);
		pos += lowbit(pos);
	}
}
int query(int pl, int pr, int rtl, int rtr, int l, int r, int k) {
	if(l == r) return l;
	int res = tree[tree[rtr].l].val - tree[tree[rtl].l].val;
	for(int i = pr; i >= 1; i -= lowbit(i)) res += tree[tree[ur[i]].l].val;
	for(int i = pl; i >= 1; i -= lowbit(i)) res -= tree[tree[ul[i]].l].val;
	int mid = (l + r) >> 1;
	if(res >= k) {
		for(int i = pr; i >= 1; i -= lowbit(i)) ur[i] = tree[ur[i]].l;
		for(int i = pl; i >= 1; i -= lowbit(i)) ul[i] = tree[ul[i]].l;
		return query(pl, pr, tree[rtl].l, tree[rtr].l, l, mid, k);
	} else {
		for(int i = pr; i >= 1; i -= lowbit(i)) ur[i] = tree[ur[i]].r;
		for(int i = pl; i >= 1; i -= lowbit(i)) ul[i] = tree[ul[i]].r;
		return query(pl, pr, tree[rtl].r, tree[rtr].r, mid + 1, r, k - res);
	}
}
int main() {
	int T;
	int tmp;
	scanf("%d", &T);
	while(T--) {
		scanf("%d %d", &n, &m);
		len = 0;
		tot = 0;
		for(int i = 1; i <= n; i++) scanf("%d", &a[i]), b[++len] = a[i], c[i] = a[i];
		for(int i = 1; i <= m; i++) {
			scanf("%s", q[i].op);
			if(q[i].op[0] == 'Q') {
				scanf("%d %d %d", &q[i].x, &q[i].y, &q[i].k);
			} else {
				scanf("%d %d", &q[i].x, &q[i].y);
				a[q[i].x] = q[i].y;
				b[++len] = q[i].y;
			}
		}
		sort(b + 1, b + 1 + len);
		len = unique(b + 1, b + 1 + len) - (b + 1);
		for(int i = 1; i <= n; i++) {
			tmp = lower_bound(b + 1, b + 1 + len, c[i]) - b;
			root[i] = update1(root[i - 1], 1, len, tmp, 1);
			rot[i] = 0;
		}
		for(int i = 1; i <= m; i++) {
			if(q[i].op[0] == 'C') {
				tmp = lower_bound(b + 1, b + 1 + len, c[q[i].x]) - b;
				update2(q[i].x, tmp, -1);
				c[q[i].x] = q[i].y;
				tmp = lower_bound(b + 1, b + 1 + len, c[q[i].x]) - b;
				update2(q[i].x, tmp, 1);
			} else {
				for(int j = q[i].x - 1; j >= 1; j -= lowbit(j)) ul[j] = rot[j];
				for(int j = q[i].y; j >= 1; j -= lowbit(j)) ur[j] = rot[j];
				printf("%d\n", b[query(q[i].x - 1, q[i].y, root[q[i].x - 1], root[q[i].y], 1, len, q[i].k)]);
			}
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值