hdu3308(线段树,区间合并)

刚开始看到题目时吓到了。。。要求上升子序列,以为是道神题,但仔细一看原来是连续上升子序列,果断变为low题了。在网上看了一些大神的代码,感觉自己的代码简洁了不少,以前学c的一些小知识点也回顾了一遍,继续奋斗!
#include <iostream>
#include<stdio.h>
#include<cstring>
#define lt(a) a<<1
#define rt(a) a<<1|1
#define md(a,b) (a+b)>>1
using namespace std;
const int MAX=1e5+1e4;
int d[MAX],T,n,m,i;
typedef struct
{
    int left,right;
    int mlen,llen,rlen,len;
    void set_len(int a)
    {
        mlen=llen=rlen=a;
    }
}P;
P p[4*MAX];
void push_up(int k)
{
    int lt=lt(k),rt=rt(k),mm=0;
    p[k].rlen=p[rt].rlen;
    p[k].llen=p[lt].llen;
    int mid=md(p[k].right, p[k].left);
    mm= d[mid]<d[mid+1]? p[lt].rlen+ p[rt].llen:0;
    p[k].mlen=max(max( p[lt].mlen, p[rt].mlen),mm);
    if( p[lt].llen== p[lt].len&&d[mid]<d[mid+1])
        p[k].llen+= p[rt].llen;
    if( p[rt].rlen == p[rt].len&&d[mid]<d[mid+1])
        p[k].rlen+= p[lt].rlen;
}
void build(int k,int l,int r)
{
    p[k].left=l;
    p[k].right=r;
    p[k].len= r-l+1;
    if(l==r)
    {
        p[k].set_len(1);
        return;
    }
    int mid=md( p[k].left, p[k].right),rt=rt(k),lt=lt(k);
    build(lt,l,mid);
    build(rt,mid+1,r);
    push_up(k);
}
void update(int k,int a,int b)
{
    if( p[k].left== p[k].right )
    {
        d[a]=b;
        return;
    }
    int mid=md( p[k].left, p[k].right),rt=rt(k),lt=lt(k);
    if(a<=mid)
        update(lt,a,b);
    else
        update(rt,a,b);
    push_up(k);
}
int query(int k,int a,int b)
{
    if( p[k].left==a && p[k].right==b)
        return  p[k].mlen;
    int mid=md( p[k].left, p[k].right),rt=rt(k),lt=lt(k);
    if( a>mid)
     return query(rt,a,b);
    else
        if(b<=mid)
        return query(lt,a,b);
    else
        {
            int mm= d[mid]<d[mid+1]?min(p[lt].rlen,mid-a+1)+ min(p[rt].llen,b-mid):0;
            return max(max(query(lt,a,mid),query(rt,mid+1,b)),mm);
        }
}
int main()
{
    char ch;
    int a,b;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)

            scanf("%d",d+i);
        build(1,0,n-1);
        while(m--)
        {
            cin>>ch;
            scanf("%d%d",&a,&b);
            if(ch=='U')
                update(1,a,b);
            else
                printf("%d\n",query(1,a,b));
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值