2024杭电多校3——1007单峰数列

补题链接

在这里插入图片描述
一道数据结构体,差分+线段树,我从没有看见过的全新版本,不过据说挺常见的。线段树维护题目里询问的东西,是否一样,单调还有单峰,小细节挺多的。建线段树开始是从2开始的,因为差分的第一个元素是 a 1 a_1 a1,同理,询问的时候也要是 l + 1 l+1 l+1,更新只需要更新两个点即可,注意询问的区间范围,还有一点就是如果询问的区间长度是1的话直接特判掉。

#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using state = array<bool,4>;//0是否一样,1是否增,2是否减,是否单峰 0否1是

const int maxn = 1e5+10;
int n,m;
i64 a[maxn],b[maxn];
state tree[maxn<<2];

state unite(state a,state b){
    state ans;
    ans[0] = a[0]&b[0];
    ans[1] = a[1]&b[1];
    ans[2] = a[2]&b[2];
    ans[3] = (a[1]&b[2]) | (a[1]&b[3]) | (a[3]&b[2]);
    return ans;
}

void pushup(int p,int l,int r){
    tree[p] = unite(tree[p*2],tree[p*2+1]);
}

void build(int p,int l,int r){
    if(l==r){
        if (b[l] == 0) tree[p][0] = 1;
        else if (b[l] > 0) tree[p][1] = 1;
        else tree[p][2] = 1;
        return;
    }
    int mid = (l+r)>>1;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    pushup(p,l,r);
}

void update(int p,int l,int r,int x,int num){//只要更新一个点即可
    if(l==r){
        b[l]+=num;
        tree[p][0]=tree[p][1]=tree[p][2]=tree[p][3]=0;
        if(b[l]==0) tree[p][0]=1;
        else if(b[l]>0) tree[p][1] = 1;
        else tree[p][2]=1;
        return;
    }
    int mid = (l+r)>>1;
    if(x<=mid)update(p*2,l,mid,x,num);
    else update(p*2+1,mid+1,r,x,num);
    pushup(p,l,r);
}

state query(int p,int l,int r,int x,int y){
    if(x<=l&&r<=y) return tree[p];
    int mid = (l+r)>>1;
    if(y<=mid) return query(p*2,l,mid,x,y);
    else if(x>mid) return query(p*2+1,mid+1,r,x,y);
    else return unite(query(p*2,l,mid,x,mid),query(p*2+1,mid+1,r,mid+1,y));
}

signed main(){
    ios;
    cin>>n;
    for(int i = 1;i<=n;++i){
        cin>>a[i];
        b[i] = a[i]-a[i-1];
    }
    build(1,2,n);
    cin>>m;
    while(m--){
        int op,l,r,x;
        cin>>op>>l>>r;
        if(op==1){
            cin>>x;
            if(l>1) update(1,2,n,l,x);
            if(r<n) update(1,2,n,r+1,-x);
        }else if(op==2){
            if(l==r){
                cout<<"1\n";
                continue;
            }
            cout<<query(1,2,n,l+1,r)[0]<<"\n";
        }else if(op==3){
            if(l == r){
                cout << "1\n";
                continue;
            }
            cout<<query(1,2,n,l+1,r)[1]<<"\n";
        }else if(op==4){
            if(l == r){
                cout << "1\n";
                continue;
            }
            cout<<query(1,2,n,l+1,r)[2]<<"\n";
        }else if(op==5){
            cout<<query(1,2,n,l+1,r)[3]<<"\n";
        }
    }
    return 0;
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值