网上各种方法都有了。。。。
去年学主席树的时候准备用树状数组套主席树水过,结果发现空间比较吃紧,就一直放在那边没敢碰。
前几天在那出来时——嗯,似乎是裸的线段树套平衡树(虽然我没有写过)……
每个线段树节点上维护一个此区间上按键值大小建立的平衡树。
操作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;
}