传送门
【题目分析】
数据结构好难啊qwq。。。。
参考了这篇博客:传送门
考虑前驱后继,用平衡树来维护,又涉及区间操作,外层再套一个线段树维护。
操作1,相当于求区间[l,r]有多少个比k小的数。
操作2比较麻烦,发现因为所有值在[0,1e8]之间,所以考虑二分求解,用类似1的操作求mid在区间的排名。
操作3,直接线段树上单点修改,记得修改原数组的值。
操作4,5直接区间求前驱后继即可。
我好菜啊qwq
【代码~】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=5e4+10;
const LL INF=2147483647;
int n,q;
int a[MAXN];
class Treap{
private:
static int cnt;
static struct node{
int son[2];
int val,pri,cnt,siz;
}t[MAXN*40];
inline int build(int val){
t[++cnt]=(node){{0,0},val,rand(),1,1};
return cnt;
}
inline void update(int p){
t[p].siz=t[t[p].son[0]].siz+t[t[p].son[1]].siz+t[p].cnt;
}
void rotate(int &p,int d){
int k=t[p].son[d];
t[p].son[d]=t[k].son[d^1];
t[k].son[d^1]=p;
update(p);
update(p=k);
}
public:
int rt;
inline void clear(){
rt=0;
}
void insert(int &p,int val){
if(!p){
p=build(val);
return ;
}
t[p].siz++;
if(t[p].val==val){
t[p].cnt++;
return ;
}
int d=t[p].val<val;
insert(t[p].son[d],val);
if(t[p].pri>t[t[p].son[d]].pri)
rotate(p,d);
}
void remove(int &p,int val){
if(t[p].val==val){
if(t[p].cnt>1){
t[p].cnt--;
t[p].siz--;
return ;
}
if(!t[p].son[0]||!t[p].son[1]){
p=t[p].son[0]+t[p].son[1];
return ;
}
int d=t[t[p].son[0]].pri>t[t[p].son[1]].pri;
rotate(p,d);
remove(p,val);
return ;
}
t[p].siz--;
int d=t[p].val<val;
remove(t[p].son[d],val);
}
int lower(int p,int val){
if(!p)
return 0;
if(t[p].val>val)
return lower(t[p].son[0],val);
if(t[p].val==val)
return t[t[p].son[0]].siz;
return t[t[p].son[0]].siz+t[p].cnt+lower(t[p].son[1],val);
}
int find_kth(int p,int k){
if(!p)
return 0;
if(t[t[p].son[0]].siz>=k)
return find_kth(t[p].son[0],k);
if(t[t[p].son[0]].siz+t[p].cnt>=k)
return t[p].val;
return find_kth(t[p].son[1],k-t[t[p].son[0]].siz-t[p].cnt);
}
int pre(int p,int val){
if(!p)
return -INF;
if(t[p].val>=val)
return pre(t[p].son[0],val);
return max(t[p].val,pre(t[p].son[1],val));
}
int suf(int p,int val){
if(!p)
return INF;
if(t[p].val<=val)
return suf(t[p].son[1],val);
return min(t[p].val,suf(t[p].son[0],val));
}
}tr[MAXN<<2];
int Read(){
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
int Treap::cnt=0;
Treap::node Treap::t[MAXN*40];
void build(int root,int l,int r){
tr[root].clear();
for(int i=l;i<=r;++i)
tr[root].insert(tr[root].rt,a[i]);
if(l==r)
return ;
int mid=l+r>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
}
int query_low(int root,int l,int r,int L,int R,int key){
if(l==L&&r==R)
return tr[root].lower(tr[root].rt,key);
int mid=l+r>>1;
if(R<=mid)
return query_low(root<<1,l,mid,L,R,key);
else{
if(L>mid)
return query_low(root<<1|1,mid+1,r,L,R,key);
else
return query_low(root<<1,l,mid,L,mid,key)+query_low(root<<1|1,mid+1,r,mid+1,R,key);
}
}
int query_pre(int root,int l,int r,int L,int R,int key){
if(L==l&&r==R)
return tr[root].pre(tr[root].rt,key);
int mid=l+r>>1;
if(R<=mid)
return query_pre(root<<1,l,mid,L,R,key);
else{
if(L>mid)
return query_pre(root<<1|1,mid+1,r,L,R,key);
else
return max(query_pre(root<<1,l,mid,L,mid,key),query_pre(root<<1|1,mid+1,r,mid+1,R,key));
}
}
int query_suf(int root,int l,int r,int L,int R,int key){
if(L==l&&r==R)
return tr[root].suf(tr[root].rt,key);
int mid=l+r>>1;
if(R<=mid)
return query_suf(root<<1,l,mid,L,R,key);
else{
if(L>mid)
return query_suf(root<<1|1,mid+1,r,L,R,key);
else
return min(query_suf(root<<1,l,mid,L,mid,key),query_suf(root<<1|1,mid+1,r,mid+1,R,key));
}
}
void update(int root,int l,int r,int x,int key){
tr[root].remove(tr[root].rt,a[x]);
tr[root].insert(tr[root].rt,key);
if(l==r)
return ;
int mid=l+r>>1;
if(x<=mid)
update(root<<1,l,mid,x,key);
else
update(root<<1|1,mid+1,r,x,key);
}
int main(){
n=Read(),q=Read();
for(int i=1;i<=n;++i)
a[i]=Read();
build(1,1,n);
while(q--){
int cz=Read();
if(cz==1){
int l=Read(),r=Read(),k=Read();
cout<<query_low(1,1,n,l,r,k)+1<<'\n';
}
if(cz==2){
int l=Read(),r=Read(),k=Read();
int ll=0,rr=1e8;
while(ll<rr){
int mid=(ll+rr+1)>>1;
if(query_low(1,1,n,l,r,mid)<k)
ll=mid;
else
rr=mid-1;
}
cout<<rr<<'\n';
}
if(cz==3){
int x=Read(),k=Read();
update(1,1,n,x,k);
a[x]=k;
}
if(cz==4){
int l=Read(),r=Read(),k=Read();
cout<<query_pre(1,1,n,l,r,k)<<'\n';
}
if(cz==5){
int l=Read(),r=Read(),k=Read();
cout<<query_suf(1,1,n,l,r,k)<<'\n';
}
}
return 0;
}