【bzoj3196】 Tyvj1730—二逼平衡树
http://www.lydsy.com/JudgeOnline/problem.php?id=3196 (题目链接)
题意
1.查询k在区间内的排名;2.查询区间内排名为k的值;3.修改某一位值上的数值;4.查询k在区间内的前驱(前驱定义为小于x,且最大的数);5.查询k在区间内的后继(后继定义为大于x,且最小的数)
Solution
修改不好搞,主席树套树状数组空间炸,最好的选择→_→:线段树套treap。
对于操作2,我们二分找到一个排名大于$k$的最小的数,然后查询这个数的前驱即可。
细节
查询前驱和后继的时候要特判一下没有找到的情况。
代码
// bzoj3196 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define inf 2147483640 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout) using namespace std; const int maxn=50010; int a[maxn],n,m; struct node { int son[2],l,r,w,val,rnd,size,tree; int& operator [] (int x) {return son[x];} }; namespace Treap { int sz;node tr[maxn*50]; void pushup(int x) { tr[x].size=tr[tr[x][0]].size+tr[tr[x][1]].size+tr[x].w; } void rotate(int &x,int p) { int y=tr[x][p]; tr[x][p]=tr[y][p^1];tr[y][p^1]=x;x=y; pushup(tr[y][p^1]);pushup(y); } void insert(int &k,int x) { if (!k) {tr[k=++sz].val=x;tr[k].rnd=rand();tr[k].size=tr[k].w=1;return;} int p=x>tr[k].val;tr[k].size++; if (x==tr[k].val) {tr[k].w++;return;} insert(tr[k][p],x); if (tr[tr[k][p]].rnd>tr[k].rnd) rotate(k,p); } void erase(int &k,int x) { if (!k) return; if (tr[k].val==x) { if (tr[k].w>1) {tr[k].w--;tr[k].size--;return;} if (tr[k][0]*tr[k][1]==0) k=tr[k][0]+tr[k][1]; else rotate(k,tr[tr[k][1]].rnd>tr[tr[k][0]].rnd),erase(k,x); } else tr[k].size--,erase(tr[k][x>tr[k].val],x); } int rank(int k,int x) { if (!k) return 0; if (x<=tr[k].val) return rank(tr[k][0],x); else return rank(tr[k][1],x)+tr[tr[k][0]].size+tr[k].w; } int find(int k,int x) { if (!k) return -1; if (tr[tr[k][0]].size<x && x<=tr[tr[k][0]].size+tr[k].w) return tr[k].val; else if (x<=tr[tr[k][0]].size) return find(tr[k][0],x); else return find(tr[k][1],x-tr[tr[k][0]].size-tr[k].w); } int pref(int k,int x) {return find(k,rank(k,x));} int suff(int k,int x) {return find(k,rank(k,x+1)+1);} } namespace Segtree { node tr[maxn<<2]; void build(int k,int s,int t) { tr[k].l=s;tr[k].r=t; for (int i=s;i<=t;i++) Treap::insert(tr[k].tree,a[i]); if (s==t) return; int mid=(s+t)>>1; build(k<<1,s,mid);build(k<<1|1,mid+1,t); } void modify(int k,int p,int val) { int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; Treap::erase(tr[k].tree,a[p]); Treap::insert(tr[k].tree,val); if (l==r) return; if (p<=mid) modify(k<<1,p,val); else modify(k<<1|1,p,val); } int rank(int k,int s,int t,int val) { int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if (s==l && t==r) return Treap::rank(tr[k].tree,val); if (t<=mid) return rank(k<<1,s,t,val); else if (s>mid) return rank(k<<1|1,s,t,val); else return rank(k<<1,s,mid,val)+rank(k<<1|1,mid+1,t,val); } int pref(int k,int s,int t,int val) { int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if (s==l && t==r) { int tmp=Treap::pref(tr[k].tree,val); return tmp==-1 ? -inf : tmp; } if (t<=mid) return pref(k<<1,s,t,val); else if (s>mid) return pref(k<<1|1,s,t,val); else return max(pref(k<<1,s,mid,val),pref(k<<1|1,mid+1,t,val)); } int suff(int k,int s,int t,int val) { int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if (s==l && t==r) { int tmp=Treap::suff(tr[k].tree,val); return tmp==-1 ? inf : tmp; } if (t<=mid) return suff(k<<1,s,t,val); else if (s>mid) return suff(k<<1|1,s,t,val); else return min(suff(k<<1,s,mid,val),suff(k<<1|1,mid+1,t,val)); } int find(int s,int t,int k) { int l=0,r=1e8,res; while (l<=r) { int mid=(l+r)>>1; if (rank(1,s,t,mid)>=k) r=mid-1,res=mid; else l=mid+1; } return pref(1,s,t,res); } } using namespace Segtree; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); for (int op,x,y,k,i=1;i<=m;i++) { scanf("%d%d%d",&op,&x,&y); if (op==1) scanf("%d",&k),printf("%d\n",rank(1,x,y,k)+1); if (op==2) scanf("%d",&k),printf("%d\n",find(x,y,k)); if (op==4) scanf("%d",&k),printf("%d\n",pref(1,x,y,k)); if (op==5) scanf("%d",&k),printf("%d\n",suff(1,x,y,k)); if (op==3) modify(1,x,y),a[x]=y; } return 0; }
This passage is made by MashiroSky.