1020 牛牛的最美味和最不美味的零食 线段树 第k个位置删除 查询动态区间最值

链接:https://ac.nowcoder.com/acm/contest/26896/1020
来源:牛客网

题目描述

牛牛为了减(吃)肥(好),希望对他的零食序列有更深刻的了解,所以他把他的零食排成一列,然后对每一个零食的美味程度都打了分,现在他有可能执行两种操作:
eat k:吃掉当前的第k个零食。右边的零食全部往左移动一位(编号减一)。

query i j:查询当前第i个零食到第j个零食里面美味度最高的和最低的零食的美味度。



输入描述:

第一行包含两个数n, m,表示原始数组的元素个数和操作的个数。第二行包括n个数,表示原始数组。以下m行,每行格式为1 k或者2 i j,其中第一个数为1表示吃掉,为2表示询问。

输出描述:

对每个询问操作输出一行,包括两个数,表示该范围内的最小值和最大值。
示例1

输入

复制
10 4
1 5 2 6 7 4 9 3 1 5
2 2 8
1 3
1 6
2 2 8

输出

复制
2 9
1 7

说明

1<=n, m<=10
6
, 1<=m<=10
6
,数组中的元素绝对值均不超过10
9

备注:


 分析

修改的时候类似于二分,要找到第pos 个数,所以如果左边的数量比pos 小,就往右边走,不然往左边走,当走到一个叶子节点说明就是第pos个数。将它的数量变成0,然后push_up操作就可以单点删除。

查询的时候,要找到 第 l 到 r 的区间。如果当前左区间的数量比 l 小,那就只能往右边走,同时由于只由cnt 是有用的,l 和 r 是没用的,所以不能根据tr[u].l 和tr[u].r 来判断当前的绝对位置,只能根据cnt 来判断相对位置,向右走了,所以 l 和 r 的相对位置都要从右边区间第一个数开始,所以都要减少 tr[ul].cnt 。

查到最后 ,l 要小于等于1 ,r 要大于等于 u 区间的右节点,这时候取区间最值即可。

//-------------------------代码----------------------------

//#define int ll
const int N = 1e6+10;
int n,m;

struct node {
    int l,r,mx,mn,cnt;
}tr[N<<2];
int a[N];

#define root tr[u]
#define left tr[ul]
#define right tr[ur]

void push_up(int u) {
    root.mn = min(left.mn,right.mn);
    root.mx = max(left.mx,right.mx);
    root.cnt = left.cnt + right.cnt;
}

void build(int u,int l,int r) {
    tr[u] = {l,r,a[l],a[l],1};
    if(l == r) rt;
    build(ul,l,tr_mid);build(ur,tr_mid+1,r);
    push_up(u);
}

void modify(int u,int pos) {
    if(tr[u].l == tr[u].r) {
        tr[u].cnt = 0;root.mn = inf;root.mx = -inf;rt;
    } 
    if(left.cnt < pos) modify(ur,pos-left.cnt);else modify(ul,pos);push_up(u);
}

int ans1=-inf,ans2=inf;
void query(int u,int l,int r) {
    if(l <= 1 && tr[u].cnt <= r) {ans1 = max(ans1,tr[u].mx);ans2 = min(ans2,tr[u].mn);rt;}
    if(r <= tr[ul].cnt) return query(ul,l,r);
    if(l > tr[ul].cnt) return query(ur,l-tr[ul].cnt,r-tr[ul].cnt);
    query(ul,l,r);query(ur,l-tr[ul].cnt,r-tr[ul].cnt);
}

void solve()
{
    cin>>n>>m;
    fo(i,1,n) cin>>a[i];
    build(1,1,n);
    while(m -- ) {
        int op,l,r,x;
        cin>>op;
        if(op == 1) {
            cin>>x;
            modify(1,x);
        } else {
            cin>>l>>r;
            ans1 = -inf,ans2 = inf;
            query(1,l,r); cout<<ans2<<' ' <<ans1<<endl;
        }
    }
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-08-10 02:38  er007  阅读(23)  评论(0)    收藏  举报