参考:https://www.cnblogs.com/RabbitHu/p/segtree.html
模板:
const int N = 1e5 + 5, M = 2e6 + 5;//M为节点个数,为Q*log(N) int root[N], lson[M], rson[M], value[M], tot = 0; //建树 void build(int &x, int l, int r) { x = ++tot; if(l == r) { scanf("%d", &value[x]); return ; } int m = (l+r) >> 1; build(lson[x], l, m); build(rson[x], m+1, r); value[x] = value[lson[x]] + value[rson[x]]; } // 将某个历史版本p位置的值加v void update(int old, int &x, int p, int v, int l, int r) { x = ++tot; lson[x] = lson[old], rson[x] = rson[old], value[x] = value[old] + v; if(l == r) return ; int m = (l+r) >> 1; if(p <= m) update(lson[x], lson[x], p, v, l, m); else update(rson[x], rson[x], p, v, m+1, r); } //访问某个历史版本L到R的区间和 int query(int L, int R, int x, int l, int r) { if(L <= l && r <= R) return value[x]; int m = (l+r) >> 1, ans = 0; if(L <= m) ans += query(L, R, lson[x], l, m); if(R > m) ans += query(L, R, rson[x], m+1, r); return ans; }
思路:
将求第k小的问题的问题转换成权值统计问题,采用可持久化线段树维护

#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pi acos(-1.0) #define LL long long //#define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pii pair<int, int> #define piii pair<pii, int> #define mem(a, b) memset(a, b, sizeof(a)) #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout); //head const int N = 5e4 + 5, M = 2e6 + 5;//M为节点个数,为Q*log(N) int root[N], lson[M], rson[M], value[M], tot = 0; int a[N], v[N]; vector<int>vc; void build(int &x, int l, int r) { x = ++tot; if(l == r) { value[x] = 0; return ; } int m = (l+r) >> 1; build(lson[x], l, m); build(rson[x], m+1, r); value[x] = value[lson[x]] + value[rson[x]]; } void update(int old, int &x, int p, int v, int l, int r) { x = ++tot; lson[x] = lson[old], rson[x] = rson[old], value[x] = value[old] + v; if(l == r) return ; int m = (l+r) >> 1; if(p <= m) update(lson[x], lson[x], p, v, l, m); else update(rson[x], rson[x], p, v, m+1, r); } int query(int x, int y, int l, int r, int k) { if(l == r) return l; int m = (l+r) >> 1, cnt = value[lson[y]] - value[lson[x]]; if(k <= cnt) return query(lson[x], lson[y], l, m, k); else return query(rson[x], rson[y], m+1, r, k-cnt); } int main() { int n, l, r, k, q; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]), vc.pb(a[i]); sort(vc.begin(), vc.end()); vc.erase(unique(vc.begin(), vc.end()), vc.end()); for (int i = 1; i <= n; i++) { int id = lower_bound(vc.begin(), vc.end(), a[i]) - vc.begin() + 1; v[id] = a[i]; a[i] = id; } build(root[0], 1, n); for (int i = 1; i <= n; i++) { update(root[i-1], root[i], a[i], 1, 1, n); } scanf("%d", &q); while(q--) { scanf("%d %d %d", &l, &r, &k); //cout << query(root[l], root[r+1], 1, n, (r-l+1-k+1)) << endl; printf("%d ", v[query(root[l], root[r+1], 1, n, (r-l+1-k+1))]); } return 0; }
思路:
树状数组套可持久线段树,注意一开始要建静态主席树,否则会爆栈

#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pi acos(-1.0) #define LL long long //#define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pii pair<int, int> #define piii pair<pii, int> #define mem(a, b) memset(a, b, sizeof(a)) #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout); //head const int N = 5e4 + 5, M = 1e4 + 5; int a[N], root[N], bitroot[N], value[N*40], lson[N*40], rson[N*40], use[N], tot, up, n; piii Q[M]; vector<int>vc; char s[M][10]; void build(int &x, int l, int r) { x = ++tot; if(l == r) { value[x] = 0; return ; } int m = l+r >> 1; build(lson[x], l, m); build(rson[x], m+1, r); value[x] = value[lson[x]] + value[rson[x]]; } int update(int old, int &x, int p, int v, int l, int r) { x = ++tot; lson[x] = lson[old], rson[x] = rson[old], value[x] = value[old] + v; if(l == r) return 0; int m = l+r >> 1; if(p <= m) update(lson[old], lson[x], p, v, l, m); else update(rson[old], rson[x], p, v, m+1, r); return 0; } void add(int x, int pos, int v) { while(x <= n) { update(bitroot[x], bitroot[x], pos, v, 1, up); x += x&-x; } } int sum(int x) { int ans = 0; while(x) { ans += value[lson[use[x]]]; x -= x&-x; } return ans; } int query(int l, int r, int k) { for (int i = l-1; i; i -= i&-i) use[i] = bitroot[i]; for (int i = r; i; i -= i&-i) use[i] = bitroot[i]; int lroot = root[l-1], rroot = `root[r]; int ll = 1 , rr = up, m = ll+rr >> 1; while(ll < rr) { int cnt = sum(r) - sum(l-1) + value[lson[rroot]] - value[lson[lroot]]; if(k <= cnt) { rr = m; for (int i = l-1; i; i -= i&-i) use[i] = lson[use[i]]; for (int i = r; i; i -= i&-i) use[i] = lson[use[i]]; lroot = lson[lroot]; rroot = lson[rroot]; } else { ll = m+1; k -= cnt; for (int i = l-1; i; i -= i&-i) use[i] = rson[use[i]]; for (int i = r; i; i -= i&-i) use[i] = rson[use[i]]; lroot = rson[lroot]; rroot = rson[rroot]; } m = ll+rr >> 1; } return ll; } int main() { int T, m; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); vc.clear(); for (int i = 1; i <= n; i++) scanf("%d", &a[i]), vc.pb(a[i]); for (int i = 0; i < m; i++) { scanf("%s", s[i]); if(s[i][0] == 'Q') { scanf("%d %d %d", &Q[i].fi.fi, &Q[i].fi.se, &Q[i].se); } else { scanf("%d %d", &Q[i].fi.fi, &Q[i].fi.se); vc.pb(Q[i].fi.se); } } sort(vc.begin(), vc.end()); vc.erase(unique(vc.begin(), vc.end()), vc.end()); up = (int)vc.size(); tot = 0; build(root[0], 1, up); for (int i = 1; i <= n; i++) a[i] = lower_bound(vc.begin(), vc.end(), a[i]) - vc.begin() + 1; for (int i = 1; i <= n; i++) update(root[i-1], root[i], a[i], 1, 1, up);//要开静态主席树,否则会爆栈,SegmentFault一整天 for (int i = 1; i <= n; i++) bitroot[i] = root[0];//树状数组每个点对应一个权值线段树,要单独开 for (int i = 0; i < m; i++) { if(s[i][0] == 'Q') printf("%d ", vc[query(Q[i].fi.fi, Q[i].fi.se, Q[i].se) - 1]); else { add(Q[i].fi.fi, a[Q[i].fi.fi], -1); int t = lower_bound(vc.begin(), vc.end(), Q[i].fi.se) - vc.begin() + 1; add(Q[i].fi.fi, t, 1); a[Q[i].fi.fi] = t; } } } return 0; } /* 2 5 3 3 2 1 4 7 Q 1 4 3 C 2 6 Q 2 5 3 5 3 3 2 1 4 7 Q 1 4 3 C 2 6 Q 2 5 3 */