[解题记录] P6812 「MCOI-02」Ancestor 先辈
P6812 「MCOI-02」Ancestor 先辈
题意简述
- 区间加
- 查询一个区间是否单调不降
解题思路
本来这题是不想写题解的,但做着做着就发现还真有小 \(trick\) 在里面
主要说说操作 \(2\) ,直接去维护的话很麻烦,因为在 pushup 的过程中,我们不仅要看左右儿子是否单调不降还要看它们相接的端点处是否
满足条件,于是我们就有一个很妙的办法:
转化为维护差分数组,这样只需要看查询的区间的最小值是否大于零就行了
如果是区间加,就在 \(l,r+1\) 上操作,如果是查询就查 \([l+1,r]\)
注意到操作涉及到了 \(r+1\) ,于是线段树就要开成 \([1,n+1]\)
\(Code\)
#include <bits/stdc++.h>
#define ls p<<1
#define rs p<<1|1
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int N=1e6+10;
const int INF=1e16;
struct node{
int min;
int lazy;
}tree[N<<2];
int m,n,a[N],maxx,k,b[N];
void pushup(int p){
tree[p].min=min(tree[ls].min,tree[rs].min);
return;
}
void build(int p,int l,int r){
if(l==r){tree[p].min=b[l];return;}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(p);
}
void upd(int p,int l,int r,int x,int y,int k){
if(l==r){
tree[p].min+=k;
return;
}
int mid=(l+r)>>1;
if(x<=mid) upd(ls,l,mid,x,y,k);
if(y>mid) upd(rs,mid+1,r,x,y,k);
pushup(p);
}
int query(int p,int l,int r,int x,int y){
int res=INF;
if(x<=l&&y>=r){return tree[p].min;}
int mid=(l+r)>>1;
if(x<=mid) res=min(res,query(ls,l,mid,x,y));
if(y>mid) res=min(res,query(rs,mid+1,r,x,y));
return res;
}
signed main(){
n=read();k=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i) b[i]=a[i]-a[i-1];
build(1,1,n+1);
for(int i=1;i<=k;++i){
int op,l,r;
op=read();l=read();r=read();
if(op==1){
int x=read();
upd(1,1,n+1,l,l,x);
upd(1,1,n+1,r+1,r+1,-x);
}
else{
if(query(1,1,n+1,l+1,r)>=0) puts("Yes");
else puts("No");
}
}
return 0;
}

浙公网安备 33010602011771号