注意空间大小,以及建树时的细节
#include
#include
#include
using namespace std;
const int maxn = 5000000 + 3;
const int N = 50000+3;
const int maxm = 100000000 + 3;
int root[maxn], n, spare[N], A[N], m, nex[N],bucket[N];
int ch[maxn][2],f[maxn],siz[maxn],num[maxn],val[maxn], cnt;
int arr[N];
inline int get(int x) { return ch[f[x]][1] == x; }
inline int ls(int x) { return ch[x][0]; }
inline int rs(int x) { return ch[x][1]; }
struct Splay_Tree
{
inline void pushup(int x)
{
siz[x] = num[x] + siz[ls(x)]+ siz[rs(x)];
}
void build(int l,int r,int& o,int fa)
{
if(l > r)return;
o = ++cnt;
int mid = (l+r) >> 1;
val[o] = arr[mid], f[o] = fa, num[o] = siz[o] = bucket[mid];
if(mid - 1 >= l) build(l,mid-1,ch[o][0],o);
if(mid + 1 <= r) build(mid+1,r,ch[o][1],o);
pushup(o);
}
inline int remove_x(int x)
{
ch[x][0] = ch[x][1] = f[x] = 0;
val[x] = num[x] = siz[x] = 0;
}
inline void rotate(int x)
{
int old = f[x], oldf = f[old], which = get(x);
ch[old][which] = ch[x][which^1], f[ch[old][which]] = old;
ch[x][which^1] = old, f[old] = x, f[x] = oldf;
if(oldf) ch[oldf][ch[oldf][1] == old] = x;
pushup(old); pushup(x);
}
inline void splay(int x,int &tar)
{
int a = f[tar];
for(int fa; (fa = f[x]) != a ;rotate(x))
if(f[fa] != a) rotate(get(x) == get(fa) ? fa : x);
tar = x;
}
inline int query_rank(int x,int ty)
{
int p = root[ty];
int tmp = 0;
while(val[p] != x && p)
{
if(x>val[p])tmp += (siz[ls(p)]+num[p]);
p = ch[p][x>val[p]];
}
tmp += siz[ls(p)];
if(p == 0)return tmp;
splay(p,root[ty]);
return siz[ls(root[ty])];
}
inline int query_num(int x,int ty)
{
int p = root[ty];
while(p)
{
if(x<=siz[ls(p)])p=ls(p);
else
{
x-=(siz[ls(p)]+num[p]);
if(x<=0)
{
splay(p,root[ty]);
return val[p];
}
p=rs(p);
}
}
return 0;
}
inline void insert_x(int x,int ty)
{
if(!root[ty])
{
root[ty] = ++cnt, val[root[ty]] = x, num[root[ty]]=1 ;
pushup(root[ty]); return;
}
int p = root[ty], fa;
while(val[p] != x && p) fa = p,p = ch[p][x > val[p]];
if(p)
{
++ num[p];
pushup(p);
splay(p,root[ty]);
}
else
{
++ cnt, num[cnt] = 1, val[cnt] = x;
ch[fa][x>val[fa]] = cnt, f[cnt] = fa;
pushup(cnt);
splay(cnt, root[ty]);
}
}
inline void delete_x(int x,int ty)
{
int p = root[ty];
while(val[p] != x && p) p = ch[p][x>val[p]];
if(p == 0)return;
splay(p,root[ty]);
if(num[root[ty]] > 1){
--num[root[ty]];
pushup(root[ty]);
return;
}
int a = root[ty];
if(!ls(root[ty]) && !rs(root[ty])){ root[ty] = 0; remove_x(a);return;}
else if(!ls(root[ty])){ root[ty] = rs(root[ty]); remove_x(a); return;}
else if(!rs(root[ty])){ root[ty] = ls(root[ty]); remove_x(a);return;}
else
{
p = ls(root[ty]);
while(rs(p))p = rs(p);
splay(p, ch[root[ty]][0]);
ch[p][1]=ch[root[ty]][1];
f[ch[p][1]]=p,f[p]=0;
pushup(p);
root[ty]=p;
remove_x(a);
}
}
inline int pre_x(int x,int ty)
{
int ans = -maxm , p = root[ty];
while(p)
{
if(val[p] < x) ans = val[p], p = ch[p][1];
else p = ch[p][0];
}
return ans;
}
inline int aft_x(int x,int ty)
{
int ans = maxm, p = root[ty];
while(p){
if(val[p] > x) ans = val[p],p = ch[p][0];
else p = ch[p][1];
}
return ans;
}
}T;
void build_Tree(int l,int r,int o)
{
if(l>r)return;
int j = 0;
for(int i = l;i <= r;++i)spare[++j] = A[i];
sort(spare+1,spare+1+j);
nex[j] = j+1;
for(int i = j-1;i >= 1;--i)
nex[i] = spare[i] == spare[i+1] ? nex[i+1] : i+1;
int pos = 0;
for(int i=1;i<=j;i=nex[i])
arr[++pos] = spare[i], bucket[pos] = nex[i] - i;
T.build(1,pos,root[o],0);
if(l == r)return;
int mid = (l+r) >> 1, ls = o<<1, rs = (o<<1)|1;
build_Tree(l, mid, ls );
build_Tree(mid+1, r,rs);
}
void update(int l,int r,int pos,int origin,int new_num, int o)
{
if(l > r)return;
T.delete_x(origin,o);
T.insert_x(new_num,o);
if(l == r) return ;
int mid = (l+r) >> 1, ls = o<<1, rs = (o<<1)|1;
if( mid >= pos) update(l, mid, pos ,origin, new_num, ls);
else update(mid+1, r, pos,origin, new_num, rs);
}
int query_rank(int l,int r,int L,int R,int num,int o)
{
if(l>=L&& r<=R) return T.query_rank(num,o);
int mid = (l+r) >> 1, ls = o<<1, rs = (o<<1)|1;
int tmp = 0;
if(L <= mid)tmp += query_rank(l,mid,L,R,num,ls);
if(R > mid) tmp += query_rank(mid+1,r,L,R,num,rs);
return tmp;
}
int query_num(int L,int R,int k)
{
int l = 1, r = maxm, fin = 0, ans;
while(l<=r)
{
int mid = (l+r) >> 1;
ans = query_rank(1,n,L,R,mid,1)+1;
if(ans <= k) l = mid + 1, fin = mid;
else r = mid - 1;
}
return fin;
}
int pre_x(int l,int r,int L,int R,int num,int o)
{
int ans = -maxm;
if(l>=L && r<=R) return T.pre_x(num,o);
int mid = (l+r) >> 1, ls = o<<1, rs = (o<<1)|1;
if(L <= mid) ans = max(ans,pre_x(l,mid,L,R,num,ls));
if(R > mid) ans = max(ans,pre_x(mid+1,r,L,R,num,rs));
return ans;
}
int aft_x(int l,int r,int L,int R,int num,int o)
{
int ans = maxm;
if(l>=L && r<=R)return T.aft_x(num,o);
int mid = (l+r) >> 1, ls = (o<<1), rs = (o<<1)|1;
if(L<=mid)ans = min(ans,aft_x(l,mid,L,R,num,ls));
if(R>mid) ans = min(ans,aft_x(mid+1,r,L,R,num,rs));
return ans;
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&A[i]);
build_Tree(1,n,1);
for(int i = 1; i <= m;++i)
{
int opt,l,r,k,pos;
scanf("%d",&opt);
if(opt == 1)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",query_rank(1,n,l,r,k,1)+1);
}
if(opt == 2)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",query_num(l,r,k));
}
if(opt == 3)
{
scanf("%d%d",&pos,&k);
update(1,n,pos,A[pos],k,1);
A[pos] = k;
}
if(opt == 4)
{
scanf("%d%d%d",&l,&r,&k);
int ans = pre_x(1,n,l,r,k,1);
if(ans == -maxm)printf("-2147483647\n");
else printf("%d\n",ans);
}
if(opt == 5)
{
scanf("%d%d%d",&l,&r,&k);
int ans = aft_x(1,n,l,r,k,1);
if(ans == maxm)printf("2147483647\n");
else printf("%d\n",ans);
}
}
return 0;
}