补题链接
一道数据结构体,差分+线段树,我从没有看见过的全新版本,不过据说挺常见的。线段树维护题目里询问的东西,是否一样,单调还有单峰,小细节挺多的。建线段树开始是从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;
}