HDU - 3308 LCIS (线段树 单点更新 区间查询)

hdu 3308 http://acm.hdu.edu.cn/showproblem.php?pid=3308

题意:要维护最长连续子序列

思路:区间查询,需要知道每段的前缀最大lcis,后缀lcis,每次用子节点来更新父节点的值的时候就要比较左右结点的后缀和前缀能否相连,左节点的lcis,右结点的lcis,这中间最长的就是父节点的lcis。

这两天深刻让我认识到了我的线段数和别人的线段树的差别。我的线段树真的写的丑死了…而且我的查询函数写的真的是。。。

这题是寒假拉过的题,然而当时不会写,今天总算是写出来了,不知道寒假的我写线段树的时候写的是些什么鬼。

代码:
//未参考他人query函数前自己写的。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
#define l(s) tr[s].l
#define r(s) tr[s].r
const int maxn = 1e5+10;
int d[maxn];
struct node
{
    int l,r,v,b,e;
}tr[maxn<<2];
void reset(int l,int r,int id)
{
    tr[id].l = l; tr[id].r = r;
    tr[id].v = tr[id].b = tr[id].e = 0;
}
int len(int id) { return tr[id].r-tr[id].l+1; }

int useson(int id)
{
    int l = tr[id].l, r = tr[id].r;
    int mid = l+r>>1;
    int res = 0;
    if(d[mid] < d[mid+1])
        res = tr[id<<1].e + tr[id<<1|1].b;
    if(tr[id<<1].b == len(id<<1) && d[mid] < d[mid+1])
        tr[id].b = tr[id<<1].b + tr[id<<1|1].b;
    else tr[id].b = tr[id<<1].b;

    if(tr[id<<1|1].e == len(id<<1|1) && d[mid] < d[mid+1])
        tr[id].e = tr[id<<1].e + tr[id<<1|1].e;
    else tr[id].e = tr[id<<1|1].e;

    tr[id].v = max(res,tr[id<<1].v);
    tr[id].v = max(tr[id].v,tr[id<<1|1].v);

    return 0;
}
void build(int l,int r,int id)
{
    reset(l,r,id);
    if(l == r)
    {   tr[id].v = tr[id].b = tr[id].e = 1; return;}
    int mid = l+r>>1;

    build(l,mid,id<<1);
    build(mid+1,r,id<<1|1);
    useson(id);
}
int add(int x,int v,int id)
{
    int l = tr[id].l, r = tr[id].r;
    if(x < l || x > r) return 0;
    if(x == l && r == l)return 0;

    int mid = l+r>>1;

    if(x <= mid) add(x,v,id<<1);
    if(x > mid) add(x,v,id<<1|1);

    useson(id);
}
node query(int ql,int qr,int id)
{
    int l = tr[id].l, r = tr[id].r;
    if(l == ql && qr == r)  return tr[id];

    node ans;
    int mid = l+r>>1;
    if(qr <= mid)  ans =  query(ql,qr,id<<1);
    else if(ql > mid)  ans = query(ql,qr,id<<1|1);
    else
    {
        node anl = query(ql,mid,id<<1);
        node anr = query(mid+1,qr,id<<1|1);
        if(d[mid] < d[mid+1]) ans.v = anl.e + anr.b;
        ans.v = max(ans.v,anl.v);
        ans.v = max(ans.v,anr.v);
        if(anl.b == anl.r-anl.l+1 && d[mid] < d[mid+1])
            ans.b = anl.b + anr.b;
        else ans.b = anl.b;

        if(anr.e == anr.r-anr.l+1 && d[mid] < d[mid+1])
            ans.e = anl.e + anr.e;
        else ans.e = anr.e;
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)
            scanf("%d",&d[i]);
        build(1,n,1);
        for(int i = 0; i < m ; i++)
        {
            char s[3]; int a,b;
            scanf("%s%d%d",s,&a,&b);
            if(s[0] == 'U')
            {
                d[++a] = b;
                add(a,b,1);
            }
            else
            {
                node ans = query(a+1,b+1,1);
                printf("%d\n",ans.v);
            }
        }
    }
    return 0;
}

//参考代码改之后的query函数
可以看出来多想一点会让代码更加清晰与精简

int query(int ql,int qr,int id)
{
    int l = tr[id].l, r = tr[id].r;
    if(l >= ql && qr >= r)  return tr[id].v;
    if(r <  ql || l > qr )  return 0;

    int ans = 0;
    int mid = l+r>>1;

    if(qr <= mid) ans = query(ql,qr,id<<1);
    else if(ql > mid) ans = query(ql,qr,id<<1|1);
    else
    {
        int ll = query(ql,mid,id<<1);
        int rr = query(mid+1,qr,id<<1|1);
        ans = max(ll,rr);
        if(d[mid] < d[mid+1])
            ans = max(ans, min(mid-ql+1,tr[id<<1].e) + min(qr-mid,tr[id<<1|1].b));
    }
    return ans;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值