bzoj 1901 動態區間第k大 (樹套樹)
阿新 • • 發佈:2019-02-01
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int Inf = 0x3f3f3f; const int maxn = 51000; inline int getnum() { int ans = 0, f = 1; char c = getchar(); if(c == '-') f = -1; while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') ans += c - '0', c = getchar(); return ans*f; } int n, m, tot; int ch[maxn*20][2], size[maxn*20], p[maxn*20], cnt[maxn*20], key[maxn*20]; int c[maxn]; struct segment { int root, l, r; int get_ship(int x) { return x == ch[p[x]][1]; } void clear(int x) { size[x] = cnt[x] = ch[x][1] = ch[x][0] = p[x] = key[x] = 0; } void up(int x) { size[x] = size[ch[x][0]] + size[ch[x][1]] + cnt[x]; } void rotate(int x) { int fa = p[x], gfa = p[p[x]], ship = get_ship(x); ch[fa][ship] = ch[x][ship^1]; p[ch[fa][ship]] = fa; ch[x][ship^1] = fa; p[fa] = x; p[x] = gfa; if(gfa) ch[gfa][fa == ch[gfa][1]] = x; up(fa); up(x); up(gfa); } void splay(int x, int tar) { for(int fa; (fa = p[x]) != tar; rotate(x)) if(p[fa] != tar) rotate((get_ship(x) == get_ship(fa))? fa:x); /* int fa = p[x]; while(1) { if(p[fa] != tar) rotate((get_ship(x) == get_ship(fa))?fa:x); rotate(x); if((fa = p[x]) == tar) break; } */ if(tar == 0) root = x; } void insert(int x) { int now = root, fa = 0; if(now == 0) { tot++; root = tot; clear(tot); key[tot] = x; size[tot] = cnt[tot] = 1; return; } while(1) { if(key[now] == x) { cnt[now]++; size[now]++; up(p[now]); splay(now, 0); return; } fa = now, now = ch[now][x > key[now]]; if(now == 0) { now = ++tot; clear(tot); cnt[now] = size[now] = 1; key[now] = x; p[now] = fa; ch[fa][x > key[fa]] = now; up(fa); splay(now, 0); return; } } } int find_no(int x) { int now = root; while(1) { if(x <= size[ch[now][0]]) now = ch[now][0]; else { x -= size[ch[now][0]] + cnt[now]; if(x <= 0) return key[now]; now = ch[now][1]; } } }//找到第x大的數字 int find_num(int x) { int now = root, ans = 0; while(1) { if(now == 0) return ans; if(x < key[now]) now = ch[now][0]; else { ans += (ch[now][0]?size[ch[now][0]]:0); if(x == key[now]) { splay(now, 0); return ans; } ans += cnt[now]; now = ch[now][1]; } } }//找數字是第多少大 int pre() { int now = ch[root][0]; while(ch[now][1]) now = ch[now][1]; return now; } int next() { int now = ch[now][1]; while(ch[now][0]) now = ch[now][0]; return now; } void delate(int x) { int no = find_num(x); if(cnt[root] > 1) { cnt[root]--; size[root]--; return; } if(!ch[root][0] && !ch[root][1]) { clear(root); root = 0; return; } if(!ch[root][0]) { int oldroot = root; root = ch[root][1]; p[root] = 0; clear(oldroot); return; } if(!ch[root][1]) { int oldroot = root; root = ch[root][0]; p[root] = 0; clear(oldroot); return; } int bigleft = pre(), oldroot = root; splay(bigleft, 0); ch[root][1] = ch[oldroot][1]; p[ch[root][1]] = root; clear(oldroot); up(root); return; } }a[maxn*4]; void build(int o, int l, int r) { a[o].l = l, a[o].r = r; for(int i = l; i <= r; i++) a[o].insert(c[i]); if(l == r) return; int mid = l + (r-l)/2; build(o*2, l, mid); build(o*2+1, mid+1, r); } void update(int o, int l, int k) { a[o].delate(c[l]); a[o].insert(k); if(a[o].l == a[o].r) return; int mid = a[o].l + (a[o].r-a[o].l)/2; if(mid >= l) update(o*2, l, k); else update(o*2+1, l, k); }//將第l個數字替換為k; int sum = 0; void find_rank(int o, int l, int r, int k) { if(a[o].l >= l && a[o].r <= r) { sum += a[o].find_num(k); return; } int mid = a[o].l + (a[o].r - a[o].l)/2; if(mid >= l) find_rank(o*2, l, r, k); if(mid < r) find_rank(o*2+1, l, r, k); }//找到k這個數字在l到r中排名為多少; void rank_k(int l, int r, int k) { int ml = 0, mr = 6, mid, ans = 0; while(ml < mr) { mid = mr - (mr-ml)/2; sum = 1; find_rank(1, l, r, mid); if(sum > k) mr = mid-1; else ml = mid; } printf("%d\n", mr); } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) scanf("%d", &c[i]); build(1, 1, n); for(int i = 1; i <= m; i++) { getchar(); char s; scanf("%c", &s); int l, r, k, x; if(s == 'Q') { scanf("%d%d%d", &l, &r, &k); rank_k(l, r, k); } if(s == 'C') { scanf("%d%d", &x, &k); update(1, x, k); } } tot = 0; memset(a, 0, sizeof(a)); } return 0; }