BJ 集训测试10 序列

http://www.elijahqi.win/archives/2790
给定一个序列要求支持以下操作 区间取Min 区间加 还有询问区间是否单调递降

使用jry线段树 2016年国家集训队论文有讲

那么我需要在每个节点维护 最大值 次大值 和最小值 每次回答询问的时候只需要看下这个区间是否满足单调或者看一下我前面的最小值是否比我当前的最大值要小 这题细节较多

维护的时候如果mx2==-1的时候我需要将区间单调的标记修改

针对区间取min这个操作我需要首先pushdown 避免修改我的时候会影响到我这层的懒标记

修改的时候如果我比这一层最小的要小那么我直接给打上修改标记即可 如果比次大的大比最大的小我只需要把最大的改过来即可 同时打上标记 如果都不属于以上的几种情况 那么我们递归下去即可 据说复杂度是log^2的 但是常数很小

#include
#include
#define N 110000
#define lc x<<1
#define rc x<<1|1
#define inf 0x7f7f7f7f
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
struct node{
    int mx,mx2,mn,flag,add,tag;
}tree[N<<2];//flag=1 describe nonincrease
int n,m,min1;
inline void update(int x){
    tree[x].mx=max(tree[lc].mx,tree[rc].mx);
    if (tree[lc].mx>tree[rc].mx&&tree[lc].mx!=tree[rc].mx){
        if (tree[lc].mx2>tree[rc].mx) tree[x].mx2=tree[lc].mx2;else tree[x].mx2=tree[rc].mx;
    }else if (tree[rc].mx2>tree[lc].mx&&tree[lc].mx!=tree[rc].mx) tree[x].mx2=tree[rc].mx2;else tree[x].mx2=tree[lc].mx;
    if (tree[lc].mx==tree[rc].mx) tree[x].mx2=max(tree[lc].mx2,tree[rc].mx2);
    tree[x].mn=min(tree[lc].mn,tree[rc].mn);if(tree[x].mx2==-1) {tree[x].flag=1;return;}
    tree[x].flag=tree[lc].flag&&tree[rc].flag&&tree[lc].mn>=tree[rc].mx;
}
inline void build(int x,int l,int r){
    if (l==r) {tree[x].mn=tree[x].mx=read();tree[x].mx2=-1;tree[x].flag=1;return;}int mid=l+r>>1;
    build(lc,l,mid);build(rc,mid+1,r);update(x);
}
inline void doadd(int x,int w){
    tree[x].mx+=w;tree[x].mn+=w;tree[x].add+=w;if (tree[x].tag) tree[x].tag+=w;if (tree[x].mx2!=-1) tree[x].mx2+=w;
}
inline void dochange(int x,int w){
    tree[x].mx=tree[x].mn=w;tree[x].mx2=-1;tree[x].tag=w;tree[x].flag=1;
}
inline void pushdown(int x){
    if (tree[x].add) doadd(lc,tree[x].add),doadd(rc,tree[x].add),tree[x].add=0;
    if (tree[x].tag){int w=tree[x].tag;tree[x].tag=0;
        if (w<=tree[lc].mn) dochange(lc,w);else
        if (w>tree[lc].mx2&&wlc].mx) tree[lc].mx=w,tree[lc].tag=w;
        if (w<=tree[rc].mn) dochange(rc,w);else
        if (w>tree[rc].mx2&&wint x,int l,int r,int l1,int r1,int w){
    if (l1<=l&&r1>=r){doadd(x,w);return;}
    int mid=l+r>>1;pushdown(x);
    if (l1<=mid) insert1(lc,l,mid,l1,r1,w);
    if (r1>mid) insert1(rc,mid+1,r,l1,r1,w);update(x);
}
inline void modify(int x,int l,int r,int l1,int r1,int w){
    if (tree[x].mx<=w) return;if (l!=r) pushdown(x);
    if(l1<=l&&r1>=r){
        if (w<=tree[x].mn) {dochange(x,w);return;}int mid=l+r>>1;
        if (w>tree[x].mx2) {tree[x].mx=w;tree[x].tag=w;return;}
        modify(lc,l,mid,l1,r1,w);modify(rc,mid+1,r,l1,r1,w);update(x);return;
    }int mid=l+r>>1;
    if (l1<=mid) modify(lc,l,mid,l1,r1,w);
    if (r1>mid) modify(rc,mid+1,r,l1,r1,w);update(x);
}
inline bool query(int x,int l,int r,int l1,int r1){
    if (l1<=l&&r1>=r){
        if(tree[x].mx>min1) return 0;
        min1=tree[x].mn;return tree[x].flag;
    }int mid=l+r>>1;pushdown(x);
    if (l1<=mid) if (!query(lc,l,mid,l1,r1)) return 0;
    if (r1>mid) if (!query(rc,mid+1,r,l1,r1)) return 0;
    return 1;
}
int main(){
    //freopen("t3.in","r",stdin);
   // freopen("t3.out","w",stdout);
    n=read();m=read();build(1,1,n);
    for (int i=1;i<=m;++i){
        int op=read(),l=read(),r=read();
        if (op==1) insert1(1,1,n,l,r,read());
        if (op==2) modify(1,1,n,l,r,read());
        if (op==3) {min1=inf;if (!query(1,1,n,l,r)) printf("%d\n",r-l+1);else puts("1");}
    }
    return 0;
}

你可能感兴趣的:(线段树)