题意:
给出一个长度为N的序列。M次操作,Q代表询问区间的第K大值,C代表修改一个位置的数。输出每次询问的第K大值。
题解:
修改第i个位置的数会影响i~n。所以可以用树状数组维护每次修改。树状数组的每个节点代表一棵树,统计结果时对应位置相加即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 60010; int t; int n, m, num; int w[maxn]; int tot; int root[maxn]; char tt[2]; vector<int> v; struct ask { int t, l, r, v; }q[10010]; struct node { int l, r, sum; }tre[maxn*40]; int use[maxn], tree[maxn]; int getid(int x) { return lower_bound(v.begin(), v.end(), x)-v.begin()+1; } void update(int l, int r, int &x, int y, int pos, int val) { tre[++tot] = tre[y]; tre[tot].sum += val; x = tot; if(l==r) return ; int mid = l+r>>1; if(pos<=mid) update(l, mid, tre[x].l, tre[y].l, pos, val); else update(mid+1, r, tre[x].r, tre[y].r, pos, val); } void add(int x, int pos, int val) { while(x <= n) { update(1, num, tree[x], tree[x], pos, val); x += x&(-x); } } int sum(int x) { int res = 0; while(x) { res += tre[tre[use[x]].l].sum; x -= x&(-x); } return res; } int query(int l, int r, int x, int y, int k, int ql, int qr) { if(l==r) return l; int mid = l+r>>1; int t = tre[tre[x].l].sum-tre[tre[y].l].sum+sum(qr)-sum(ql); if(t>=k) { for(int i = qr; i; i-=i&(-i)) use[i] = tre[use[i]].l; for(int i = ql; i; i-=i&(-i)) use[i] = tre[use[i]].l; return query(l, mid, tre[x].l, tre[y].l, k, ql, qr); } else { for(int i = qr; i > 0; i-=i&(-i)) use[i] = tre[use[i]].r; for(int i = ql; i > 0; i-=i&(-i)) use[i] = tre[use[i]].r; return query(mid+1, r, tre[x].r, tre[y].r, k-t, ql, qr); } } int main() { scanf("%d", &t); while(t--) { tot = 0; v.clear(); memset(tree, 0, sizeof(tree)); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d", &w[i]); v.push_back(w[i]); } for(int i = 1; i <= m; i++) { scanf("%s%d%d", tt, &q[i].l, &q[i].r); if(tt[0]=='C') q[i].t = 0, v.push_back(q[i].r); else scanf("%d", &q[i].v), q[i].t = 1; } sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); num = v.size(); for(int i = 1; i <= n; i++) update(1, num, root[i], root[i-1], getid(w[i]), 1); for(int i = 1; i <= m; i++) { if(q[i].t) { for(int j = q[i].r; j; j-=j&(-j)) use[j] = tree[j]; for(int j = q[i].l-1; j; j-=j&(-j)) use[j] = tree[j]; printf("%d ", v[query(1, num, root[q[i].r], root[q[i].l-1], q[i].v, q[i].l-1, q[i].r)-1]); } else { add(q[i].l, getid(w[q[i].l]), -1); add(q[i].l, getid(q[i].r), 1); w[q[i].l] = q[i].r; } } } }