Loading

[解题记录] P6812 「MCOI-02」Ancestor 先辈

P6812 「MCOI-02」Ancestor 先辈

题意简述

  1. 区间加
  2. 查询一个区间是否单调不降

解题思路

本来这题是不想写题解的,但做着做着就发现还真有小 \(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;
}

posted @ 2022-01-22 22:03  Miraii  阅读(50)  评论(0)    收藏  举报