题目链接:点击打开链接
思路:我们都知道, treap可以维护整个区间内的数的大小关系, 那么我们在线段树的每个节点上建一棵treap, 那么对于一个n个数的每一个数, 他都会经历logn个结点,所以总的结点数是n * logn。 然后二分答案ans, 询问区间内<=ans的个数来判断二分方向就行了。
一个防止超内存的黑科技:开一个数组做内存池。
细节参见代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <stack> #include <bitset> #include <cstdlib> #include <cmath> #include <ctime> #include <set> #include <list> #include <deque> #include <map> #include <queue> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; typedef long double ld; const ld eps = 1e-9, PI = 3.1415926535897932384626433832795; const int mod = 1000000000 + 7; const int INF = 0x3f3f3f3f; // & 0x7FFFFFFF const int seed = 131; const ll INF64 = ll(1e18); const int maxn = 5e4 + 10; int T,n,m; struct node { node *ch[2]; int r, v, s; int cmp(int x) const { if(x == v) return -1; return x < v ? 0 : 1; } void maintain() { s = 1; if(ch[0] != NULL) s += ch[0]->s; if(ch[1] != NULL) s += ch[1]->s; } } *root[maxn<<2], table[900000], *top; node *newnode(int x) { top -> v = x ; top -> s = 1 ; top -> r = rand() ; top -> ch[0] = top -> ch[1] = NULL ; return top ++ ; } void rotate(node* &o, int d) { node* k = o->ch[d^1]; //旋转, 使得优先级满足堆的意义 o->ch[d^1] = k->ch[d]; k->ch[d] = o; o->maintain(); k->maintain(); o = k; } void insert(node* &o, int x) { if(o == NULL) o = newnode(x); else { int d = (x < o->v ? 0 : 1); insert(o->ch[d], x); if(o->ch[d]->r > o->r) rotate(o, d^1); } o->maintain(); } void remove(node* &o, int x) { if(o == NULL) return ; int d = o->cmp(x); if(d == -1) { node* u = o; if(o->ch[0] != NULL && o->ch[1] != NULL) { int d2 = (o->ch[0]->r > o->ch[1]->r ? 1 : 0); rotate(o, d2); remove(o->ch[d2], x); } else { if(o->ch[0] == NULL) o = o->ch[1]; else o = o->ch[0]; } } else remove(o->ch[d], x); if(o != NULL) o->maintain(); } int kth(node* o, int k) { if(o == NULL || k <= 0 || k > o->s) return 0; int s = (o->ch[0] != NULL ? o->ch[0]->s : 0); if(k == s+1) return o->v; else if(k <= s) return kth(o->ch[0], k); else return kth(o->ch[1], k-s-1); } void build(int l, int r, int o, int pos, int v) { int m = (l + r) >> 1; insert(root[o], v); if(l == r) return ; if(pos <= m) build(l, m, o<<1, pos, v); else build(m+1, r, o<<1|1, pos, v); } int getsum(node* root, int k) { if(root == NULL) return 0; int ans = 0; int d = k < root -> v ? 0 : 1; if(d == 0) ans += getsum(root->ch[d], k); else { ans += 1 + (root -> ch[0] != NULL ? root->ch[0]->s : 0); ans += getsum(root->ch[1], k); } return ans; } void update(int l, int r, int o, int pos, int old, int v) { int m = (l + r) >> 1; remove(root[o], old); insert(root[o], v); if(l == r) return ; if(pos <= m) update(l, m, o<<1, pos, old, v); else update(m+1, r, o<<1|1, pos, old, v); } int query(int L, int R, int l, int r, int o, int x) { int m = (l + r) >> 1; if(L <= l && r <= R) return getsum(root[o], x); int ans = 0; if(L <= m) ans += query(L, R, l, m, o<<1, x); if(m < R) ans += query(L, R, m+1, r, o<<1|1, x); return ans; } int erfen(int L, int R, int k) { int l = 1, r = INF, mid; while(r > l) { mid = (l + r) >> 1; int cur = query(L, R, 1, n, 1, mid); if(cur >= k) r = mid; else l = mid + 1; } return l; } int a[maxn], pos, v, l, r; char op[2]; int main() { scanf("%d",&T); while(T--) { top = table; memset(root, 0, sizeof(root)); scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); build(1, n, 1, i, a[i]); } while(m--) { scanf("%s",op); if(op[0] == 'C') { scanf("%d%d",&pos, &v); update(1, n, 1, pos, a[pos], v); a[pos] = v; } else { scanf("%d%d%d",&l,&r,&v); int ans = erfen(l, r, v); printf("%d\n",ans); } } } return 0; }