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 (动态开点权值线段树 + 树状数组)
洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)