单点更新,区间查询,适合用线段树来解决。其中注意删除操作的实现。查询区间最大最小值时,注意右子树的标号控制。

更多注释详见代码

#include <bits/stdc++.h>
#define L(u) (u<<1)
#define R(u) (u<<1|1)
using namespace std;
const int mx=1000001;
struct Tree
{
    int lch,rch,Min,Max,num;
} tree[mx<<2];//Min:区间最小值 Max:区间最大值 num:区间内尚存的,即未被删除的元素数目
int d[mx],m,n,l,r,ans1,ans2;
char s;
void read(int &k)
{
    int f=1;
    char c=getchar();
    while ((c<48||c>57)&&c!='-') c=getchar();
    if (c=='-') f=-1,c=getchar();
    k = 0;
    while (48<=c&&c<=57) k=k*10+c-48,c=getchar();
    k=f*k;
}
void Pushup(int u)
{
    tree[u].Max=max(tree[L(u)].Max,tree[R(u)].Max);
    tree[u].Min=min(tree[L(u)].Min,tree[R(u)].Min);
    tree[u].num=tree[L(u)].num+tree[R(u)].num;
}
void Build(int u,int l,int r)
{//建树。根节点编号是1
    tree[u].lch=l;
    tree[u].rch=r;
    if (l==r)
	{//叶节点
        tree[u].Max=tree[u].Min=d[l];
        tree[u].num=1;
        return ;
    }
    int mid=(l+r)>>1;
    Build(L(u),l,mid);//递归,建左子树
    Build(R(u),mid+1,r);//递归,建右子树
    Pushup(u);//建完两棵子树,向上更新一下
}
void Delete(int u,int num)
{//删除节点的操作实现。这个num是待删元素的标号
    if((tree[u].lch==tree[u].rch))
	{//叶节点。删的就是它
        tree[u].num--;//没有元素了
        tree[u].Min=2147483647;
        tree[u].Max=-2147483648;
        return;
    }
    int n1=tree[L(u)].num;
    if(num<=n1) Delete(L(u),num);//标号≤左子树所含元素个数,则待删元素在左子树上,递归找它
    else Delete(R(u),num-n1);//不是左子树就是右子树啦。注意这里往右子树递归的时候,标号减去左子树所含元素数目
    Pushup(u);//少了元素了,需要更新
}
void Query(int u,int l,int r)
{
    if (l==1&&tree[u].num==r)
	{
        ans1=min(ans1,tree[u].Min);
        ans2=max(ans2,tree[u].Max);
        return ;
    }
    int n1=tree[L(u)].num,n2=tree[R(u)].num;
    if (l<=n1&&r>n1)
	{//待查询区间跨了左右两棵子树
        Query(L(u),l,n1);
        Query(R(u),1,r-n1);
    } else if (l<=n1&&r<=n1) Query(L(u),l,r);//左子树
    else if (l>n1&&r<=n1+n2) Query(R(u),l-n1,r-n1);//右子树
}
int main()
{
    read(n);
    read(m);
    for (int i=1; i<=n; ++i) read(d[i]);
    for (int i=1; i<=4*n; ++i) tree[i].Min=2147483647,tree[i].Max=-2147483648;
    Build(1,1,n);
    while (m--)
	{
        scanf(" %c",&s);
        if (s=='1')
		{
            scanf("%d",&l);
            Delete(1,l);
        }
		else
		{
            scanf("%d%d",&l,&r);
            ans1=2147483647,ans2=-2147483648;
            Query(1,l,r);
            printf("%d %d\n",ans1,ans2);
        }
    }
    return 0;
}