网上各种方法都有了。。。。
去年学主席树的时候准备用树状数组套主席树水过,结果发现空间比较吃紧,就一直放在那边没敢碰。
前几天在那出来时——嗯,似乎是裸的线段树套平衡树(虽然我没有写过)……
每个线段树节点上维护一个此区间上按键值大小建立的平衡树。
操作1、直接找区间内有多少个数小于他即刻。
操作2、二分答案后就变成了操作1
操作3、一路修改下去吧。。。。
操作4、在线段树上的每一个子区间找前驱,保留最大值
操作5、在线段树上的每一个子区间找后继,保留最小值
于是就这样码下去了。。。。。
树套树也不是很难写嘛,就算难写也是很好调的。。。。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int Maxn=1000005, INF=1e8; int fa[Maxn],size[Maxn],son[Maxn][2]; int root[Maxn],w[Maxn],a[Maxn]; int n,m,type,tot,i,ans,l,r,k; void rotate(int x,int ft,int K){ if (fa[ft]){ if (son[fa[ft]][0]==ft) son[fa[ft]][0]=x; else son[fa[ft]][1]=x; } fa[x] = fa[ft]; if (son[x][K^1]) fa[son[x][K^1]]=ft; son[ft][K] = son[x][K^1]; son[x][K^1] = ft; fa[ft] = x; size[ft] = size[son[ft][0]] + size[son[ft][1]] + 1; } void Splay(int p,int x,int y){ int ft, gf; while (fa[x]!=y){ ft = fa[x]; gf = fa[ft]; if (gf==y){ if (son[ft][0]==x) rotate(x,ft,0); if (son[ft][1]==x) rotate(x,ft,1); } else { if (son[ft][0]==x && son[gf][0]==ft) rotate(ft,gf,0), rotate(x,ft,0); if (son[ft][1]==x && son[gf][1]==ft) rotate(ft,gf,1), rotate(x,ft,1); if (son[ft][0]==x && son[gf][1]==ft) rotate(x,ft,0), rotate(x,gf,1); if (son[ft][1]==x && son[gf][0]==ft) rotate(x,ft,1), rotate(x,gf,0); } } size[x] = size[son[x][0]] + size[son[x][1]] + 1; if (y==0) root[p] = x; } int binary(int l,int r){ if (l>r) return 0; int mid = (l+r)>>1; son[mid][0] = binary(l,mid-1); son[mid][1] = binary(mid+1,r); if (son[mid][0]) fa[son[mid][0]]=mid; if (son[mid][1]) fa[son[mid][1]]=mid; size[mid] = size[son[mid][0]] + size[son[mid][1]] + 1; return mid; } int build_bin(int l,int r){ for (int i=l;i<=r;i++) w[tot+i-l+1] = a[i]; sort(w+tot+1,w+tot+(r-l+1)+1); int ret = binary(tot+1,tot+r-l+1); tot = tot+r-l+1; return ret; } void build_seg(int p,int l,int r){ root[p] = build_bin(l,r); if (l==r) return; int mid = (l+r)>>1; build_seg(p*2+1,l,mid); build_seg(p*2+2,mid+1,r); } int find_rank(int p,int k){ int t=root[p], ret=0; while (true){ if (t==0) break; if (w[t]<k){ ret+=size[son[t][0]]+1; t=son[t][1]; } else t=son[t][0]; } return ret; } int find_knumber_rank(int p,int l,int r,int L,int R,int k){ if (L>r || l>R) return 0; if (L<=l && R>=r) return find_rank(p,k); int mid=(l+r)>>1; int ret1 = find_knumber_rank(p*2+1,l,mid,L,R,k); int ret2 = find_knumber_rank(p*2+2,mid+1,r,L,R,k); return ret1+ret2; } int find_pos(int p,int k){ int t=root[p]; while (true){ if (t==0) break; if (w[t]==k) return t; if (w[t]>k) t=son[t][0]; else t=son[t][1]; } return 0; } void del(int p,int t){ Splay(p,t,0); int L=son[t][0], R=son[t][1]; while (son[L][1]) L=son[L][1]; while (son[R][0]) R=son[R][0]; if (L==0 && R==0) {root[p]=0;return;} if (L==0) {Splay(p,R,0);son[R][0]=0;Splay(p,R,0);return;} if (R==0) {Splay(p,L,0);son[L][1]=0;Splay(p,L,0);return;} Splay(p,L,0); Splay(p,R,L); son[R][0]=0; Splay(p,R,0); } void ins(int p,int d){ int t=root[p]; if (t==0){ root[p]=d; size[d]=1; fa[d]=0; return; } while (true){ if (w[t]>w[d]){ if (son[t][0]==0) {son[t][0]=d;fa[d]=t;break;} else t=son[t][0]; } else { if (son[t][1]==0) {son[t][1]=d;fa[d]=t;break;} else t=son[t][1]; } } Splay(p,d,0); } void modify(int p,int l,int r,int pos,int k){ int t = find_pos(p,a[pos]); del(p,t); w[t] = k; ins(p,t); if (l==r) return; int mid=(l+r)>>1; if (pos<=mid) modify(p*2+1,l,mid,pos,k); else modify(p*2+2,mid+1,r,pos,k); } int prev_number(int p,int k){ int t=root[p], ret=-INF; while (true){ if (t==0) break; if (w[t]<k){ ret = w[t]; t=son[t][1]; } else t=son[t][0]; } return ret; } int find_prev(int p,int l,int r,int L,int R,int k){ if (l>R || L>r) return -INF; if (L<=l && R>=r) return prev_number(p,k); int mid=(l+r)>>1; int ret1 = find_prev(p*2+1,l,mid,L,R,k); int ret2 = find_prev(p*2+2,mid+1,r,L,R,k); return max(ret1,ret2); } int next_number(int p,int k){ int t=root[p], ret=INF; while (true){ if (t==0) break; if (w[t]>k){ ret = w[t]; t=son[t][0]; } else t=son[t][1]; } return ret; } int find_next(int p,int l,int r,int L,int R,int k){ if (l>R || L>r) return INF; if (L<=l && R>=r) return next_number(p,k); int mid=(l+r)>>1; int ret1 = find_next(p*2+1,l,mid,L,R,k); int ret2 = find_next(p*2+2,mid+1,r,L,R,k); return min(ret1,ret2); } void work1(){ scanf("%d%d%d",&l,&r,&k); ans = find_knumber_rank(0,1,n,l,r,k)+1; printf("%d\n",ans); } void work2(){ scanf("%d%d%d",&l,&r,&k); int L = -INF, R = INF, Mid; while (L<=R){ Mid = (L+R)/2; int t = find_knumber_rank(0,1,n,l,r,Mid); if (k>t) ans = Mid, L=Mid+1; else R=Mid-1; } printf("%d\n",ans); } void work3(){ int pos; scanf("%d%d",&pos,&k); modify(0,1,n,pos,k); a[pos] = k; } void work4(){ scanf("%d%d%d",&l,&r,&k); ans = find_prev(0,1,n,l,r,k); printf("%d\n",ans); } void work5(){ scanf("%d%d%d",&l,&r,&k); ans = find_next(0,1,n,l,r,k); printf("%d\n",ans); } int main(){ //freopen("3196.in","r",stdin); //freopen("3196.out","w",stdout); scanf("%d%d",&n,&m); for (i=1;i<=n;i++) scanf("%d",&a[i]); build_seg(0,1,n); while (m--){ scanf("%d",&type); if (type==1) work1(); if (type==2) work2(); if (type==3) work3(); if (type==4) work4(); if (type==5) work5(); } return 0; }