P2617 第K小(动态可持久化线段树)

Posted jpphy0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2617 第K小(动态可持久化线段树)相关的知识,希望对你有一定的参考价值。

问题

P2617 第K小 - https://www.luogu.com.cn/problem/P2617

分析

代码

#include<bits/stdc++.h>
using namespace std;
const int MXN = 2e5+5;
int N, n = 0, M, tot = -1, ver[MXN];
int a[MXN<<1], b[MXN<<1];
struct TreeNode{
	int l, r; // 左右子树
	int s; // 出现次数
}tree[MXN<<9];
struct Query{
	char op[2];
	int x, y, z;
}q[MXN];
int query(int node, int l, int r, int L, int R){
	TreeNode &rt = tree[node];
	if(l == L && r == R) return rt.s;
	int mid = (l+r)>>1;
	if(R <= mid) return query(rt.l, l, mid, L, R);
	else return query(rt.r, mid+1, r, L, R);
}
int sum(int p, int L, int R){ // p:树的时间编号
	int res = 0;
	for( ; p > 0; p -= p&-p) res += query(ver[p], 1, n, L, R);
	return res;
}
int build(int l, int r){
	int root = ++tot;
	TreeNode &rt = tree[root];
	rt.s = 0, rt.l = 0, rt.r = 0;
	return root;
}
int update(int node, int l, int r, int p, int val = 1){
	int root = ++tot;
	TreeNode &rt = tree[root];
	rt = tree[node];
	if(l == r){rt.s += val; return root;}
	int mid = (l+r)>>1;
	if(p <= mid) rt.l = update(rt.l, l, mid, p, val);
	else rt.r = update(rt.r, mid+1, r, p, val);
	rt.s = tree[rt.l].s + tree[rt.r].s;
	return root;
}
int ask(int pre, int lst, int l, int r, int k){
	if(l == r) return l;
	int mid = (l+r)>>1;
	int x = sum(lst, l, mid) - sum(pre, l, mid);
	if(x >= k) return ask(pre, lst, l, mid, k);
	else return ask(pre, lst, mid+1, r, k-x);
}
int main(){
	int x, y;
	scanf("%d%d", &N, &M);
	for(int i = 1; i <= N; ++i) scanf("%d", a+i), b[i] = a[i];
	for(int i = 1; i <= M; ++i){
		scanf("%s%d%d", q[i].op, &q[i].x, &q[i].y);
		if(q[i].op[0] == 'C'){
			b[++n+N] = q[i].y;
			continue;
		}
		scanf("%d", &q[i].z);
	}
	sort(b+1, b+N+n+1);
	n = unique(b+1, b+N+n+1) - b - 1;
	memset(ver, 0, sizeof ver);
	ver[0] = build(1, n);
	for(int i = 1; i <= N; ++i){
		x = lower_bound(b+1, b+n+1, a[i]) - b;
		for(int p = i; p <= N; p += p&-p)
			ver[p] = update(ver[p], 1, n, x, 1);
	}
	for(int i = 1; i <= M; ++i){
		if(q[i].op[0] == 'Q'){
			printf("%d\\n", b[ask(q[i].x-1, q[i].y, 1, n, q[i].z)]);
			continue;
		}		
		if(a[q[i].x] != q[i].y){
			x = lower_bound(b+1, b+n+1, a[q[i].x]) - b;
			y = lower_bound(b+1, b+n+1, q[i].y) - b;
			for(int p = q[i].x; p <= N; p += p&-p)
				ver[p] = update(ver[p], 1, n, x, -1);
			for(int p = q[i].x; p <= N; p += p&-p)
				ver[p] = update(ver[p], 1, n, y, 1);
			a[q[i].x] = q[i].y; // 更新
		}
	}
    return 0;
}

以上是关于P2617 第K小(动态可持久化线段树)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P2617 Dynamic Rankings

P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)

区间第K小(可持久化线段树)

洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)

HDU 2665.Kth number-无修改区间第K小-可持久化线段树(主席树)模板

可持久化线段树