Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)

Posted 昵称很长很长真是太好了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)相关的知识,希望对你有一定的参考价值。

题意:
操作1:把x位置的数字修改成y。
操作2:查询[l,r]之间不下降序列的个数。
题解:
线段树维护区间和问题 (这是套路,想不到只能说做题少别打我)
用五个变量进行维护。
sum区间总个数
llen从左边这个数字开始往右最长不下降序列长度(往右端最长延伸)
rlen从右边这个数字开始往左最长不上升序列长度(往左端最长延伸)
lnum这个区间最左端的数字
rnum这个区间最右端的数字

很明显lnum和rnum很好维护,直接pushup即可。

如果左子树的右端小于等于右子树的左端。

sum则需要在两个区间进行合并时重新计算。
那么则需要减去左子树右端连续的一部分做的贡献和右子树左端连续的一部分做的贡献,加上这两个长度总共做的贡献即可(详细看代码)。

llen需要判断左子树是否为完全上升序列,如果是,那么更新llen为左子树llen+右子树llen
否则llen为左子树llen
同理
rlen需要判断右子树是否为完全上升序列,如果是,那么更新llen为右子树rlen+右子树rlen
否则rlen为左子树rlen

如果不小于等于
那么sum=左子树sum+右子树sum
llen为左子树llen
rlen为左子树rlen

代码:
之前听课听的那种维护方式在query和pushup之间不兼容,需要多写很多东西,所以换了种写法。

#include<bits/stdc++.h>
#define endl '\\n'
#define int long long
using namespace std;
const int maxn=2e5+10;

int a[maxn];
//int sumlen[maxn<<2],lnum[maxn<<2],rnum[maxn<<2];
//int llen[maxn<<2],rlen[maxn<<2];
struct Node
    int sum,llen,rlen,lnum,rnum;
tree[maxn<<2];

inline int cal(int x)
    return (x*(x+1))/2;

Node mer(Node ls,Node rs,int start,int ends)
    Node res=0,0,0,ls.lnum,rs.rnum;
    int mid=(start+ends)>>1;
    if(ls.rnum<=rs.lnum)
        res.sum=ls.sum+rs.sum-cal(ls.rlen)-cal(rs.llen)+cal(ls.rlen+rs.llen);  //sum
        if(ls.llen==mid-start+1)
            res.llen=ls.llen+rs.llen;
        
        else res.llen=ls.llen;
        if(rs.rlen==ends-mid)
            res.rlen=rs.rlen+ls.rlen;
        
        else res.rlen=rs.rlen;
    
    else
        res.sum=ls.sum+rs.sum;
        res.llen=ls.llen;
        res.rlen=rs.rlen;
    
    return res;


void push_up(int node,int start,int ends)
    tree[node]=mer(tree[node<<1],tree[node<<1|1],start,ends);

void build(int node,int start,int ends)
    if(start==ends)
        tree[node]=1,1,1,a[start],a[start];
        return ;
    
    int mid=start+ends>>1;
    build(node<<1,start,mid);
    build(node<<1|1,mid+1,ends);
    push_up(node,start,ends);

void update(int node,int start,int ends,int pos,int val)
    if(start==ends)
        tree[node].lnum=tree[node].rnum=val;
        return ;
    
    int mid=(start+ends)>>1;
    if(pos<=mid) update(node<<1,start,mid,pos,val);
    else update(node<<1|1,mid+1,ends,pos,val);
    push_up(node,start,ends);



Node query(int node,int start,int ends,int l,int r)
    if(l<=start&&ends<=r)
        return tree[node];
    
    int mid=start+ends>>1;
    Node ls,rs;
    if(l<=mid&&mid<r) return mer(query(node<<1,start,mid,l,r),query(node<<1|1,mid+1,ends,l,r),start,ends);
    else if(r<=mid) return query(node<<1,start,mid,l,r);
    else if(mid<l) return query(node<<1|1,mid+1,ends,l,r);


signed main()
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,q;
    cin>>n>>q;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    
    build(1,1,n);
    for(int i=1;i<=q;i++)
        int opt;
        cin>>opt;
        if(opt==1)
            int x,y;
            cin>>x>>y;
            update(1,1,n,x,y);
        
        else
            int x,y;
            cin>>x>>y;
            Node ans=query(1,1,n,x,y);
            cout<<ans.sum<<endl;
        
    
    //printf("hello world" "welcome to haut");




以上是关于Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #742 div.2 A-F题解

Codeforces Round #742 div.2 A-F题解

Codeforces Round #742 (Div. 2)A-E

Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma 线段树

Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma 线段树

Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)