解题思路
这里写的是常数巨大的线段树套(splay),卡了半天常才过。首先线段树每个节点挂一个(splay),(splay)中的元素即为线段树管辖的区间中的数。对于操作(1),发现(rk)是可以求和的,所以直接在线段树上找到对应区间求(rk)即可,时间复杂度(O(nlog^2n));对于操作(2),发现不具有可加性,所以要二分转化成求(rk),时间复杂度(O(nlog^3n));对于操作(3),直接在线段树中找到对应区间,(splay)中删数加数即可,时间复杂度(O(nlog^2n));对于操作(4,5),直接在对应后继然后取(min)取(max)即可,时间复杂度(O(nlog^2n))
代码
// luogu-judger-enable-o2
#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=50005;
const int M=N*40;
const int inf=2147483647;
inline int rd(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
void out(int x){
if(!x) return; out(x/10); putchar('0'+x%10);
}
inline void OUT(int x) {
if(!x) putchar('0');
else (x>0)?(out(x)):(putchar('-'),out(-x));
putchar('
');
}
inline int min(int x,int y) {return x<y?x:y;}
inline int max(int x,int y) {return x>y?x:y;}
int n,m,rt,tot=2,zz[N],ans,Max,Min=inf;
struct Splay{
int val[M],ch[M][2],fa[M],siz[M],cnt[M],rt[M];
inline bool check(int x){return (x==ch[fa[x]][1]);}
inline void pushup(int x) {siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];}
inline void rotate(int x){
int y=fa[x],z=fa[y]; bool chk=check(x);
if(z) ch[z][check(y)]=x; ch[y][chk]=ch[x][chk^1];
fa[ch[x][chk^1]]=y; ch[x][chk^1]=y; fa[y]=x; fa[x]=z;
pushup(y); pushup(x);
}
inline void splay(int x,int top,int id){
for(;fa[x]!=top;rotate(x))
if(fa[fa[x]]!=top) rotate(check(fa[x])==check(x)?fa[x]:x);
if(!top) rt[id]=x;
}
inline void find(int x,int y){
int now=rt[y];
while(1){
if(val[now]==x) {splay(now,0,y); return;}
if(x>val[now]) now=ch[now][1];
else now=ch[now][0];
}
}
inline int get_pre(int x){
int now=ch[rt[x]][0]; if(!now) return 2;
while(ch[now][1]) now=ch[now][1];
return now;
}
inline int get_nxt(int x){
int now=ch[rt[x]][1]; if(!now) return 1;
while(ch[now][0]) now=ch[now][0];
return now;
}
inline void insert(int x,int y){
if(!rt[x]) {rt[x]=++tot; val[tot]=y; siz[tot]=cnt[tot]=1; return;}
register int now=rt[x],lst=0;
while(1){
if(val[now]==y) {cnt[now]++; splay(now,0,x); return;}
lst=now; now=ch[now][y>val[now]];
if(!now) {
now=++tot; val[now]=y; cnt[now]=siz[now]=1;
ch[lst][y>val[lst]]=now; fa[now]=lst;
splay(now,0,x); return;
}
}
}
inline void erase(int x,int y){
find(y,x); register int now=rt[x],Pre,Nxt;
if(cnt[now]>1) cnt[now]--;
else if(!ch[now][0] && !ch[now][1]) rt[x]=0;
else if(!ch[now][0]) fa[ch[now][1]]=0,rt[x]=ch[now][1];
else if(!ch[now][1]) fa[ch[now][0]]=0,rt[x]=ch[now][0];
else {
Pre=get_pre(x); Nxt=get_nxt(x);
splay(Pre,0,x); splay(Nxt,Pre,x);
ch[Nxt][0]=0; splay(Nxt,0,x);
}
}
inline int rk(int x,int y){
register int now=rt[x],ret=0;
while(1){
if(!now) return ret;
if(val[now]==y) {ret+=siz[ch[now][0]]; splay(now,0,x); return ret;}
if(val[now]<y) ret+=siz[ch[now][0]]+cnt[now],now=ch[now][1];
else now=ch[now][0];
}
}
}tree2;
struct Segment_Tree{
#define mid ((l+r)>>1)
int ls[M],rs[M];
void update(int x,int l,int r,int pos,int w){
tree2.insert(x,w); if(l==r) return;
if(pos<=mid) update(x<<1,l,mid,pos,w);
else update(x<<1|1,mid+1,r,pos,w);
}
void modify(int x,int l,int r,int pos,int w){
tree2.erase(x,zz[pos]); tree2.insert(x,w);
if(l==r) return;
if(pos<=mid) modify(x<<1,l,mid,pos,w);
else modify(x<<1|1,mid+1,r,pos,w);
}
void query_rk(int x,int l,int r,int L,int R,int k){
// if(L<=l && r<=R) cout<<l<<" "<<r<<" "<<x<<" "<<tree2.rk(x,k)<<endl;
if(L<=l && r<=R) {ans+=tree2.rk(x,k); return; }
if(L<=mid) query_rk(x<<1,l,mid,L,R,k);
if(mid<R) query_rk(x<<1|1,mid+1,r,L,R,k);
}
void query_pre(int x,int l,int r,int L,int R,int k){
if(L<=l && r<=R) {
tree2.insert(x,k);
ans=max(ans,tree2.val[tree2.get_pre(x)]);
tree2.erase(x,k);
return;
}
if(L<=mid) query_pre(x<<1,l,mid,L,R,k);
if(mid<R) query_pre(x<<1|1,mid+1,r,L,R,k);
}
void query_nxt(int x,int l,int r,int L,int R,int k){
if(L<=l && r<=R) {
tree2.insert(x,k);
ans=min(ans,tree2.val[tree2.get_nxt(x)]);
tree2.erase(x,k);
return;
}
if(L<=mid) query_nxt(x<<1,l,mid,L,R,k);
if(mid<R) query_nxt(x<<1|1,mid+1,r,L,R,k);
}
#undef mid
}tree1;
inline int query_kth(int l,int r,int lim){
int L=Min,R=Max,mid,ret;
while(L<=R){
mid=(L+R)>>1; ans=1; tree1.query_rk(1,1,n,l,r,mid);
if(ans>lim) R=mid-1; else ret=mid,L=mid+1;
}
return ret;
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
tree2.val[2]=-inf; tree2.val[1]=inf;
n=rd(),m=rd(); int x,l,r,k,opt,L,R;
for(register int i=1;i<=n;++i)
zz[i]=rd(),tree1.update(1,1,n,i,zz[i]),Max=max(Max,zz[i]),Min=min(Min,zz[i]);
while(m--){
opt=rd();
if(opt==1){
l=rd(),r=rd(),k=rd(); ans=1;
tree1.query_rk(1,1,n,l,r,k);
OUT(ans);
}
else if(opt==2){
l=rd(),r=rd(),k=rd();
OUT(query_kth(l,r,k));
}
else if(opt==3){
x=rd(),k=rd();
tree1.modify(1,1,n,x,k);
zz[x]=k; Max=max(Max,k); Min=min(Min,k);
}
else if(opt==4){
l=rd(),r=rd(),k=rd(); ans=-inf;
tree1.query_pre(1,1,n,l,r,k);
OUT(ans);
}
else if(opt==5){
l=rd(),r=rd(),k=rd(); ans=inf;
tree1.query_nxt(1,1,n,l,r,k);
OUT(ans);
}
}
return 0;
}