事实上对于第一类询问和第二类询问我们可以分别处理。
第二类询问的处理方法是非常显然的。由于只有插入而没有删除操作,因此,第二类询问的答案只会缩小、不会增大。
故而,我们对整个数列的值维护一个Splay,每一次插入一个新的数以后,用它和它的前驱与它和它的后继的差的绝对值来更新第二类的答案。
这可以用multiset来简易地实现。
对于第一类询问,我们发现,维护这个值其实并不是难点——用线段树或者平衡树都可以轻松实现。问题在于,如何在插入新的数之后保持这个值。
我们仔细思考,发现,对于任意一段区间来说,它对答案的贡献只有三个:这个区间的答案,这个区间的左端点和这个区间的右端点。
故而,我们建一棵线段树或者平衡树,维护这三个信息(个人认为线段树比较科学。)每一次修改则修改对应的节点,然后递归向上更新即可。
这样就做完了,个人觉得实现难度还是比较低的。
#include<iostream>
#include<cstdio>
#include<set>
#define LS (X<<1)
#define RS (X<<1|1)
#define MID ((L+R)>>1)
inline int Abs(int X){
return X>0?X:-X;
}
inline int Min(int A,int B){
return A<B?A:B;
}
std::multiset<int> st;
int ansS=0x3f3f3f3f;
int n,m,a[500005];
class SegmentTree{
private:
class Node{
public:
int l;
int r;
int dlt;
inline Node(){
dlt=0x3f3f3f3f;
}
inline void init(int V){
l=r=V;
}
inline void psh(int V){
dlt=Min(dlt,Abs(r-V));
r=V;
}
};
Node tr[1100000];
inline void updt(int X){
tr[X].l=tr[LS].l;
tr[X].r=tr[RS].r;
tr[X].dlt=Min(Min(tr[LS].dlt,tr[RS].dlt),Abs(tr[LS].r-tr[RS].l));
}
inline void build(int L,int R,int X){
if(L>R){
return;
}
if(L==R){
tr[X].init(a[L]);
return;
}
build(L,MID,LS),build(MID+1,R,RS);
updt(X);
}
inline void push(int L,int R,int X,int A,int V){
if(L>R){
return;
}
if(L==R){
tr[X].psh(V);
return;
}
A>MID?push(MID+1,R,RS,A,V):push(L,MID,LS,A,V);
updt(X);
}
inline void prnt(int L,int R,int X){
if(L>R){
return;
}
if(L==R){
printf("%d:[%d,%d,%d] ",X,tr[X].l,tr[X].r,tr[X].dlt);
return;
}
prnt(L,MID,LS),prnt(MID+1,R,RS);
}
public:
inline void PUSH(int X,int K){
push(1,n,1,X,K);
}
inline void BUILD(){
build(1,n,1);
}
inline int QUERYG(){
return tr[1].dlt;
}
inline void PRINT(){
prnt(1,n,1);
puts("");
}
};
inline void STPUSH(int K){
st.insert(K);
std::multiset<int> ::iterator it=st.find(K);
int ans1,ans2;
++it;
if(it!=st.end()){
ans1=*it;
}else{
ans1=0x3f3f3f3f;
}
--it;
if(it!=st.begin()){
--it;
ans2=*it;
}else{
ans2=0x3f3f3f3f;
}
ans1=Abs(K-ans1),ans2=Abs(K-ans2);
ansS=Min(ansS,Min(ans1,ans2));
}
SegmentTree T;
void init(){
scanf("%d%d",&n,&m);
int x;
for(int i=1;i<=n;++i){
scanf("%d",a+i);
STPUSH(a[i]);
}
T.BUILD();
char op[10];
int k;
for(int i=1;i<=m;++i){
std::cin>>op;
switch(op[4]){
case 'R':{
scanf("%d%d",&x,&k);
T.PUSH(x,k);
STPUSH(k);
break;
}
case 'G':{
printf("%d\n",T.QUERYG());
break;
}
case 'S':{
printf("%d\n",ansS);
break;
}
case 'P':{
T.PRINT();
break;
}
}
}
}
int main(){
init();
return 0;
}