hdu 3308-线段树基本区间合并

这题明显是线段树基本区间合并,由于第一次写也遇到了不少问题,下面将赘述。。


首先对于区间合并问题,tr里面要有rsum,lsum,msum,分别表示左连续最大,右连续最大,和区间最大,为什么这么表示,当然是为了合并操作。


先说pushup部分,不是简单的sum或者max了,按套路来,如果合并有特殊条件要加特殊条件,对于这道题要加判断arr[mi]和arr[mi+1],

由于这道题没有pushdown,所以还算简单,下一步打算做一个有pushdown的,

queue里面也有技巧,就是当mid在s和t中间时要用min确保合并的时候(当然是符合合并条件时)得到正确答案,以防多算了不在s和t中间的。

midify就是简单的midify加pushup就可以了显而易见。

由于是第一道区间合并还有理解不透彻的地方,希望继续努力,蒟蒻加油。。。

#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
const int MAX=1000000;
struct pr {
    int msum,lsum,rsum;
    int left,right;                    
}tr[MAX+10];
int n;
inline int ll(int k) {return 2*k;}          //左边的下标
inline int rr(int k) {return 2*k+1;}         //右边的下标
inline int mid(int kk1,int kk2) {return (kk1+kk2)>>1;}
int arr[MAX];

void pushup(int k){//m=r-l+1;
    int l=tr[k].left,r=tr[k].right;
    int mi=mid(l,r);
    tr[k].lsum =tr[ll(k)].lsum;
    tr[k].rsum =tr[rr(k)].rsum;//如果合并有条件则加条件
    if(arr[mi]<arr[mi+1]){
        if (tr[k].lsum == mi-l+1) tr[k].lsum+=tr[rr(k)].lsum;
        if (tr[k].rsum == r-mi) tr[k].rsum+=tr[ll(k)].rsum;
        tr[k].msum = max(tr[rr(k)].lsum+tr[ll(k)].rsum,max(tr[ll(k)].msum,tr[rr(k)].msum));
        return;
    }
    tr[k].msum = max(tr[ll(k)].msum,tr[rr(k)].msum);
}

void build(int k,int s,int t) {
    tr[k].left=s;tr[k].right=t;
    if(s==t) {tr[k].lsum=tr[k].rsum=tr[k].msum=1;return;}               
    build(ll(k),s,mid(s,t));
    build(rr(k),mid(s,t)+1,t);
    pushup(k);    //pushup
    return;
}

void modify(int k,int s,int x) {
    int l=tr[k].left,r=tr[k].right;
    if(l==r){
        arr[s]=x;
        return ;
    }
    int mi=mid(l,r);
    if(s<=mi) modify(ll(k),s,x);
    else if(s>mi) modify(rr(k),s,x);
    pushup(k);
}
int query(int k,int s,int t) {
    int l=tr[k].left,r=tr[k].right;
    if(l==s&&r==t) return tr[k].msum;
    int mi=mid(l,r);
    int res=0;
    if (t<=mi) res=query(ll(k),s,t);
    else if(s>mi) res=query(rr(k),s,t);
    else {
        res=max(query(ll(k),s,mi),query(rr(k),mi+1,t));
        if(arr[mi]<arr[mi+1]){
            res=max(res,min(mi-s+1,tr[ll(k)].rsum)+min(t-mi,tr[rr(k)].lsum));
        }
    }
    return res;
}

int main(){

    int t;
    cin>>t;
    int n,m;
    while(t--){
        memset(tr,0,sizeof(tr));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&arr[i]);
        }
        build(1,1,n);
        char c[2];
        int a,b;
        for(int i=0;i<m;i++){
            scanf("%s%d%d",c,&a,&b);
            if(c[0]=='Q'){
                printf("%d\n",query(1,a+1,b+1));
            }
            else{
                modify(1,a+1,b);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值