即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

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

编程语言 m0_37253730 20℃ 0评论

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

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

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

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

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

代码:


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

#include 
#include 
#include 
#include 

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;
}

转载请注明:CodingBlog » HDU – 3308 LCIS (线段树 单点更新 区间查询)

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情