hrbust 1524 最大(区间合并)

给包含n个数的初始序列,A[1], A[2], ..., A[n]。
给q多个操作,操作如下:
1 a b v, 把[a, b] 的值改为v,即A[a] = A[a+1] = ... = A[b] = v。
2 a b, 查询[a, b] 之间的相同数的连续和最大值。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define havemid int m=(l+r)>>1
#define left (rt<<1)
#define right (rt<<1|1)
const int maxn=100010;
int lva[maxn<<2];     // 最左面的值      
int rva[maxn<<2];     // 最右面的值 
int lnum[maxn<<2];    // 最左面的数的个数
int rnum[maxn<<2];    // 最右面的数的个数
int mov[maxn<<2];     // 区间最大连续值
int add[maxn<<2];     // 延迟标记  
int va[maxn];
void pushup(int l,int r,int rt){
    havemid;
    lva[rt]=lva[left];        //父节点的左值=左儿子左值  
    rva[rt]=rva[right];       //右
    lnum[rt]=lnum[left];      //父节点的左连续个数=左儿子左连续个数
    rnum[rt]=rnum[right];     //右
    mov[rt]=max(mov[left],mov[right]);  //区间最值=左区间最值和右区间中的最大
    if(lva[left]==lva[right]&&lnum[left]==m-l+1)lnum[rt]+=lnum[right];
    //左区间左值=右区间左值&&左区间左连续充满做区间,父区间左连续就可以+上右区间左连续
    if(rva[right]==rva[left]&&rnum[right]==r-m)rnum[rt]+=rnum[left]; 
    if(rva[left]==lva[right])mov[rt]=max(mov[rt],rva[left]*(rnum[left]+lnum[right]));
    //左区间右值=右区间左值 父节点最值和中间区间的最值比较 要最大的
}                                                               
void pushdown(int l,int r,int rt){ 
    if(add[rt]!=-1){
        havemid;
        add[left]=add[right]=add[rt];  //延迟标记向下传递
        lva[left]=lva[right]=rva[left]=rva[right]=add[rt];  //各种值都是add的值了
        lnum[left]=rnum[left]=m-l+1;    //连续的个数充满着整个区间
        lnum[right]=rnum[right]=r-m;
        mov[left]=(m-l+1)*add[rt];      //区间和最值为个数*变成的那个数
        mov[right]=(r-m)*add[rt];
        add[rt]=-1;
    }
}
void build(int l,int r,int rt){
    add[rt]=-1;
    if(l==r){
        scanf("%d",&va[l]);
        lva[rt]=va[l];      //各种值为输入的那个值
        rva[rt]=va[l];
        mov[rt]=va[l];
        lnum[rt]=rnum[rt]=1;//各种连续为一
        return ;
    }
    havemid;
    build(lson);
    build(rson);
    pushup(l,r,rt);
}
void update(int L,int R,int c,int l,int r,int rt){
    if(L<=l&&r<=R){                 
        add[rt]=c;
        mov[rt]=(r-l+1)*c;
        lva[rt]=rva[rt]=c;
        lnum[rt]=rnum[rt]=r-l+1;
        return ;
    }
    pushdown(l,r,rt);
    havemid;
    if(L<=m)update(L,R,c,lson);
    if(R>m)update(L,R,c,rson);
    pushup(l,r,rt);
}
int query(int L,int R,int l,int r,int rt){
     if(L<=l&&r<=R){
        return mov[rt];
    }
    havemid;
    pushdown(l,r,rt);
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else {
        int tmp=0;
        if(rva[left]==lva[right])   //左的右值和右的左值相等 就可以合并
            tmp=rva[left]*(min(rnum[left],m-L+1)+min(lnum[right],R-m));
            //不能超出查询区间
        int t1=query(L,R,lson);
        int t2=query(L,R,rson);
        int ret=max(tmp,max(t1,t2));
        return ret;
    }
}
int main(){
    int n,m,op,a,b,c,ca=1;
    while(scanf("%d",&n)!=EOF){
        build(1,n,1);
        scanf("%d",&m);
        printf("Case %d:\n",ca++);
        while(m--){
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d%d",&a,&b,&c);
                update(a,b,c,1,n,1);
            }
            else {
                scanf("%d%d",&a,&b);
                int res=query(a,b,1,n,1);
                printf("%d\n",res);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值