现在的位置: 首页 > 综合 > 正文

[HDU 3308]LCIS[线段树][区间合并]

2018年03月17日 ⁄ 综合 ⁄ 共 1757字 ⁄ 字号 评论关闭

hdu3308 LCIS

给定10^5个数,区间查询严格上升的最长连续序列长度,点更新某个数.

线段树,区间合并

有三个数组,msum, lsum, rsum,分别存总最长,左端串长,右端串长

一直错的一个地方是:query,合并的时候,若左右儿子可以合并,应该取max{min[左儿子右长,实际右长],min[右儿子左长,实际左长]},而不是max{min[左儿子最大长,实际右长],min[右儿子最大长,实际左长]}.因为有可能儿子最大长并不是由中间接上的那一段产生的

这种细节非常复杂的题分析清楚算法很重要.Debug实在很难找.其实是原理性错误...

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 100005;
int num[maxn];
int lsum[maxn<<2] , rsum[maxn<<2] , msum[maxn<<2];

void PushUp(int l, int r,int rt) {
    lsum[rt] = lsum[rt<<1];
    rsum[rt] = rsum[rt<<1|1];
    int m = (l+r)>>1;
    if(num[m]<num[m+1])
    {
        if (lsum[rt] == m - l + 1) lsum[rt] += lsum[rt<<1|1];
        if (rsum[rt] == r - m) rsum[rt] += rsum[rt<<1];
        msum[rt] = max(lsum[rt<<1|1] + rsum[rt<<1] , max(msum[rt<<1] , msum[rt<<1|1]));
    }
    else
    {
        msum[rt] = max(msum[rt<<1] , msum[rt<<1|1]);
    }


}///总最长为左和 or 右和 or 左右拼接中间的段
void build(int l,int r,int rt) {
    msum[rt] = lsum[rt] = rsum[rt] = 1;//区间长度
    if (l == r) return ;
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    PushUp(l,r,rt);
}
void update(int p,int c,int l,int r,int rt) {
    if (l==r) {
        msum[rt] = lsum[rt] = rsum[rt] = 1;
        return ;
    }
    int m = (l + r) >> 1;
    if (p <= m) update(p , c , lson);
    if (m < p) update(p , c , rson);
    PushUp(l,r,rt);
}
int query(int L,int R,int l,int r,int rt) {
    if(L==l&&r==R)//?
    {
        return msum[rt];
    }
    int m = (l+r)>>1;
    if(R<=m)
    {
        return query(L, R, lson);
    }
    else if(L>m)
    {
        return query(L, R, rson);
    }
    else if(num[m]>=num[m+1])
    {

        return max(query(L, m, lson),query(m+1, R, rson));
    }
    else
    {
        int a = query(L,m,lson), b = query(m+1, R, rson);
        int ls = min(rsum[rt<<1],m - L + 1), rs = min(lsum[rt<<1|1], R - m);
        return max(max(a,b),ls+rs);
    }
}
int main() {
    int n , m, T;
    scanf("%d",&T);
    while (T--) {
        scanf("%d %d",&n,&m);
        for(int i=0;i<n;i++)
        {
            scanf("%d",num+i);
        }
        build(0 , n-1 , 1);
        int a , b;
        char op[2];
        while(m--)
        {
            scanf("%s",op);
            if (op[0] == 'U') {
                scanf("%d %d",&a,&b);
                num[a] = b;
                update(a , b , 0 , n-1 , 1);
            }
            else {
                scanf("%d %d",&a,&b);
                printf("%d\n",query(a , b , 0 , n-1 , 1));
            }
        }
    }
    return 0;
}

抱歉!评论已关闭.