BZOJ-3065 带插入区间K小值
替罪羊树套权值线段树,其中替罪羊树可以满足插入的操作。
#include <cstdlib> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <cctype> #define rep(i, l, r) for(int i=l; i<=r; i++) #define clr(x, c) memset(x, c, sizeof(x)) #define inf 0x7fffffff #define ll long long #define maxn 80010 #define maxl 70010 #define l(x) Left[x] #define r(x) Right[x] #define s(x) Size[x] #define k(x) Key[x] #define t(x) Tree[x] #define ls(x) Size[Left[x]] #define rs(x) Size[Right[x]] #define a 0.8 using namespace std; inline int read() { int x=0, f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x*f; } //========================================================================================= struct node { node *l, *r; int sum; node () {sum=0; l=r=NULL;} } *blank=new(node); void Add(int l, int r, int k, node*&t) { if (t==blank) t=new(node), t->l=t->r=blank; t->sum++; if (l==r) return; int mid=(l+r)>>1; if (k<=mid) Add(l, mid, k, t->l); else Add(mid+1, r, k, t->r); } void Del(int l, int r, int k, node*&t) { t->sum--; if (l==r) return; int mid=(l+r)>>1; if (k<=mid) Del(l, mid, k, t->l); else Del(mid+1, r, k, t->r); } //========================================================================================= int Left[maxn], Right[maxn], Key[maxn], Size[maxn], V=0, roof, dfn[maxn], top; node *Tree[maxn]; void Build(int l, int r, int &t) { if (l>r) {t=0; return;} int mid=(l+r)>>1; t=dfn[mid], t(t)=blank, s(t)=r-l+1; rep(i, l, r) Add(0, maxl, k(dfn[i]), t(t)); Build(l, mid-1, l(t)), Build(mid+1, r, r(t)); } node *range[maxn]; int p[maxn], nr, np; void ranging(int l, int r, int t) //BST查找区间 { if (r<ls(t)) ranging(l, r, l(t)); //全在左边 else if (l>ls(t)) ranging(l-ls(t)-1, r-ls(t)-1, r(t)); //全在右边 else if (!l && r==s(t)-1) range[++nr]=t(t); //整棵树都是 else //分跨两边 { p[++np]=k(t); if (l<ls(t)) ranging(l, ls(t)-1, l(t)); if (r>ls(t)) ranging(0, r-ls(t)-1, r(t)); } } void getrange(int l, int r){nr=np=0; ranging(l-1, r-1, roof);} void dfs(int t){if (l(t)) dfs(l(t)); dfn[++top]=t; if (r(t)) dfs(r(t));} //DFS序 void Recycle(node *t) //回收节点 { if (!t->sum) return; if (t->l) Recycle(t->l); if (t->r) Recycle(t->r); delete(t); } void reBuild(int &t) { top=0; dfs(t); rep(i, 1, top) Recycle(t(dfn[i])); Build(1, top, t); } //========================================================================================= bool Insert(int r, int k, int h, int &t) { if (!t) { t=++V; s(t)=1, k(t)=k, l(t)=r(t)=0, t(t)=blank; Add(0, maxl, k, t(t)); return h>log(V)/log(1/a); } bool flag; if (r<=ls(t)) flag=Insert(r, k, h+1, l(t)); else flag=Insert(r-ls(t)-1, k, h+1, r(t)); s(t)=ls(t)+rs(t)+1; Add(0, maxl, k, t(t)); if (flag && (max(ls(t), rs(t)) > a*s(t))) {reBuild(t); return false;} return flag; } int Change(int r, int k, int t) { if (ls(t)==r) { int v=k(t); Del(0, maxl, k(t), t(t)); Add(0, maxl, k(t)=k, t(t)); return v; } int v; if (r<ls(t)) v=Change(r, k, l(t)); else v=Change(r-ls(t)-1, k, r(t)); Del(0, maxl, v, t(t)); Add(0, maxl, k, t(t)); return v; } int Query(int l, int r, int rank) { rank--; getrange(l, r); int L=0, R=maxl; while (L<R) { int mid=(L+R)>>1, sum=0; rep(i, 1, nr) sum+=range[i]->l->sum; rep(i, 1, np) sum+=(p[i]>=L && p[i]<=mid) ? 1 : 0; if (rank<sum) {rep(i, 1, nr) range[i]=range[i]->l; R=mid;} else {rank-=sum; rep(i, 1, nr) range[i]=range[i]->r; L=mid+1;} } return L; } //========================================================================================= int n, m, w[maxn], last=0; int main() { blank->l=blank->r=blank; n=read(); rep(i, 1, n) w[i]=read(); l(0)=r(0)=s(0)=0; rep(i, 1, n) dfn[i]=++V, k(V)=w[i]; Build(1, n, roof); m=read(); while (m--) { char ch=getchar(); while (ch!='Q' && ch!='M' && ch!='I') ch=getchar(); if (ch=='Q') { int x=read()^last, y=read()^last, z=read()^last; printf("%d\n", last=Query(x, y, z)); } else if (ch=='I') { int x=read()^last, y=read()^last; Insert(x-1, y, 0, roof); } else { int x=read()^last, y=read()^last; Change(x-1, y, roof); } } return 0; }